diff --git a/index.html b/index.html index 3d56e5c..8bba5d9 100644 --- a/index.html +++ b/index.html @@ -7,86 +7,89 @@ rotme - -
0
- - - - - - - - - - - - + \ No newline at end of file diff --git a/pixi.js b/pixi.js new file mode 100644 index 0000000..0f14618 --- /dev/null +++ b/pixi.js @@ -0,0 +1,42805 @@ +/*! + * PixiJS - v8.1.6 + * Compiled Wed, 05 Jun 2024 07:57:10 UTC + * + * PixiJS is licensed under the MIT License. + * http://www.opensource.org/licenses/mit-license + */ +var PIXI = (function (exports) { + 'use strict'; + + "use strict"; + var __defProp$11 = Object.defineProperty; + var __defProps$n = Object.defineProperties; + var __getOwnPropDescs$n = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$11 = Object.getOwnPropertySymbols; + var __hasOwnProp$11 = Object.prototype.hasOwnProperty; + var __propIsEnum$11 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$11 = (obj, key, value) => key in obj ? __defProp$11(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$11 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$11.call(b, prop)) + __defNormalProp$11(a, prop, b[prop]); + if (__getOwnPropSymbols$11) + for (var prop of __getOwnPropSymbols$11(b)) { + if (__propIsEnum$11.call(b, prop)) + __defNormalProp$11(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$n = (a, b) => __defProps$n(a, __getOwnPropDescs$n(b)); + var ExtensionType = /* @__PURE__ */ ((ExtensionType2) => { + ExtensionType2["Application"] = "application"; + ExtensionType2["WebGLPipes"] = "webgl-pipes"; + ExtensionType2["WebGLPipesAdaptor"] = "webgl-pipes-adaptor"; + ExtensionType2["WebGLSystem"] = "webgl-system"; + ExtensionType2["WebGPUPipes"] = "webgpu-pipes"; + ExtensionType2["WebGPUPipesAdaptor"] = "webgpu-pipes-adaptor"; + ExtensionType2["WebGPUSystem"] = "webgpu-system"; + ExtensionType2["CanvasSystem"] = "canvas-system"; + ExtensionType2["CanvasPipesAdaptor"] = "canvas-pipes-adaptor"; + ExtensionType2["CanvasPipes"] = "canvas-pipes"; + ExtensionType2["Asset"] = "asset"; + ExtensionType2["LoadParser"] = "load-parser"; + ExtensionType2["ResolveParser"] = "resolve-parser"; + ExtensionType2["CacheParser"] = "cache-parser"; + ExtensionType2["DetectionParser"] = "detection-parser"; + ExtensionType2["MaskEffect"] = "mask-effect"; + ExtensionType2["BlendMode"] = "blend-mode"; + ExtensionType2["TextureSource"] = "texture-source"; + ExtensionType2["Environment"] = "environment"; + return ExtensionType2; + })(ExtensionType || {}); + const normalizeExtension = (ext) => { + if (typeof ext === "function" || typeof ext === "object" && ext.extension) { + if (!ext.extension) { + throw new Error("Extension class must have an extension object"); + } + const metadata = typeof ext.extension !== "object" ? { type: ext.extension } : ext.extension; + ext = __spreadProps$n(__spreadValues$11({}, metadata), { ref: ext }); + } + if (typeof ext === "object") { + ext = __spreadValues$11({}, ext); + } else { + throw new Error("Invalid extension type"); + } + if (typeof ext.type === "string") { + ext.type = [ext.type]; + } + return ext; + }; + const normalizeExtensionPriority = (ext, defaultPriority) => { + var _a; + return (_a = normalizeExtension(ext).priority) != null ? _a : defaultPriority; + }; + const extensions = { + /** @ignore */ + _addHandlers: {}, + /** @ignore */ + _removeHandlers: {}, + /** @ignore */ + _queue: {}, + /** + * Remove extensions from PixiJS. + * @param extensions - Extensions to be removed. + * @returns {extensions} For chaining. + */ + remove(...extensions2) { + extensions2.map(normalizeExtension).forEach((ext) => { + ext.type.forEach((type) => { + var _a, _b; + return (_b = (_a = this._removeHandlers)[type]) == null ? void 0 : _b.call(_a, ext); + }); + }); + return this; + }, + /** + * Register new extensions with PixiJS. + * @param extensions - The spread of extensions to add to PixiJS. + * @returns {extensions} For chaining. + */ + add(...extensions2) { + extensions2.map(normalizeExtension).forEach((ext) => { + ext.type.forEach((type) => { + var _a, _b; + const handlers = this._addHandlers; + const queue = this._queue; + if (!handlers[type]) { + queue[type] = queue[type] || []; + (_a = queue[type]) == null ? void 0 : _a.push(ext); + } else { + (_b = handlers[type]) == null ? void 0 : _b.call(handlers, ext); + } + }); + }); + return this; + }, + /** + * Internal method to handle extensions by name. + * @param type - The extension type. + * @param onAdd - Function handler when extensions are added/registered {@link StrictExtensionFormat}. + * @param onRemove - Function handler when extensions are removed/unregistered {@link StrictExtensionFormat}. + * @returns {extensions} For chaining. + */ + handle(type, onAdd, onRemove) { + var _a; + const addHandlers = this._addHandlers; + const removeHandlers = this._removeHandlers; + if (addHandlers[type] || removeHandlers[type]) { + throw new Error(`Extension type ${type} already has a handler`); + } + addHandlers[type] = onAdd; + removeHandlers[type] = onRemove; + const queue = this._queue; + if (queue[type]) { + (_a = queue[type]) == null ? void 0 : _a.forEach((ext) => onAdd(ext)); + delete queue[type]; + } + return this; + }, + /** + * Handle a type, but using a map by `name` property. + * @param type - Type of extension to handle. + * @param map - The object map of named extensions. + * @returns {extensions} For chaining. + */ + handleByMap(type, map) { + return this.handle( + type, + (extension) => { + if (extension.name) { + map[extension.name] = extension.ref; + } + }, + (extension) => { + if (extension.name) { + delete map[extension.name]; + } + } + ); + }, + /** + * Handle a type, but using a list of extensions with a `name` property. + * @param type - Type of extension to handle. + * @param map - The array of named extensions. + * @param defaultPriority - Fallback priority if none is defined. + * @returns {extensions} For chaining. + */ + handleByNamedList(type, map, defaultPriority = -1) { + return this.handle( + type, + (extension) => { + const index = map.findIndex((item) => item.name === extension.name); + if (index >= 0) + return; + map.push({ name: extension.name, value: extension.ref }); + map.sort((a, b) => normalizeExtensionPriority(b.value, defaultPriority) - normalizeExtensionPriority(a.value, defaultPriority)); + }, + (extension) => { + const index = map.findIndex((item) => item.name === extension.name); + if (index !== -1) { + map.splice(index, 1); + } + } + ); + }, + /** + * Handle a type, but using a list of extensions. + * @param type - Type of extension to handle. + * @param list - The list of extensions. + * @param defaultPriority - The default priority to use if none is specified. + * @returns {extensions} For chaining. + */ + handleByList(type, list, defaultPriority = -1) { + return this.handle( + type, + (extension) => { + if (list.includes(extension.ref)) { + return; + } + list.push(extension.ref); + list.sort((a, b) => normalizeExtensionPriority(b, defaultPriority) - normalizeExtensionPriority(a, defaultPriority)); + }, + (extension) => { + const index = list.indexOf(extension.ref); + if (index !== -1) { + list.splice(index, 1); + } + } + ); + } + }; + + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } + + function getDefaultExportFromNamespaceIfPresent (n) { + return n && Object.prototype.hasOwnProperty.call(n, 'default') ? n['default'] : n; + } + + function getDefaultExportFromNamespaceIfNotNamed (n) { + return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n; + } + + function getAugmentedNamespace(n) { + if (n.__esModule) return n; + var f = n.default; + if (typeof f == "function") { + var a = function a () { + if (this instanceof a) { + return Reflect.construct(f, arguments, this.constructor); + } + return f.apply(this, arguments); + }; + a.prototype = f.prototype; + } else a = {}; + Object.defineProperty(a, '__esModule', {value: true}); + Object.keys(n).forEach(function (k) { + var d = Object.getOwnPropertyDescriptor(n, k); + Object.defineProperty(a, k, d.get ? d : { + enumerable: true, + get: function () { + return n[k]; + } + }); + }); + return a; + } + + var eventemitter3$1 = {exports: {}}; + + var eventemitter3 = eventemitter3$1.exports; + + (function (module) { + 'use strict'; + + var has = Object.prototype.hasOwnProperty + , prefix = '~'; + + /** + * Constructor to create a storage for our `EE` objects. + * An `Events` instance is a plain object whose properties are event names. + * + * @constructor + * @private + */ + function Events() {} + + // + // We try to not inherit from `Object.prototype`. In some engines creating an + // instance in this way is faster than calling `Object.create(null)` directly. + // If `Object.create(null)` is not supported we prefix the event names with a + // character to make sure that the built-in object properties are not + // overridden or used as an attack vector. + // + if (Object.create) { + Events.prototype = Object.create(null); + + // + // This hack is needed because the `__proto__` property is still inherited in + // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. + // + if (!new Events().__proto__) prefix = false; + } + + /** + * Representation of a single event listener. + * + * @param {Function} fn The listener function. + * @param {*} context The context to invoke the listener with. + * @param {Boolean} [once=false] Specify if the listener is a one-time listener. + * @constructor + * @private + */ + function EE(fn, context, once) { + this.fn = fn; + this.context = context; + this.once = once || false; + } + + /** + * Add a listener for a given event. + * + * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. + * @param {(String|Symbol)} event The event name. + * @param {Function} fn The listener function. + * @param {*} context The context to invoke the listener with. + * @param {Boolean} once Specify if the listener is a one-time listener. + * @returns {EventEmitter} + * @private + */ + function addListener(emitter, event, fn, context, once) { + if (typeof fn !== 'function') { + throw new TypeError('The listener must be a function'); + } + + var listener = new EE(fn, context || emitter, once) + , evt = prefix ? prefix + event : event; + + if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; + else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); + else emitter._events[evt] = [emitter._events[evt], listener]; + + return emitter; + } + + /** + * Clear event by name. + * + * @param {EventEmitter} emitter Reference to the `EventEmitter` instance. + * @param {(String|Symbol)} evt The Event name. + * @private + */ + function clearEvent(emitter, evt) { + if (--emitter._eventsCount === 0) emitter._events = new Events(); + else delete emitter._events[evt]; + } + + /** + * Minimal `EventEmitter` interface that is molded against the Node.js + * `EventEmitter` interface. + * + * @constructor + * @public + */ + function EventEmitter() { + this._events = new Events(); + this._eventsCount = 0; + } + + /** + * Return an array listing the events for which the emitter has registered + * listeners. + * + * @returns {Array} + * @public + */ + EventEmitter.prototype.eventNames = function eventNames() { + var names = [] + , events + , name; + + if (this._eventsCount === 0) return names; + + for (name in (events = this._events)) { + if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); + } + + if (Object.getOwnPropertySymbols) { + return names.concat(Object.getOwnPropertySymbols(events)); + } + + return names; + }; + + /** + * Return the listeners registered for a given event. + * + * @param {(String|Symbol)} event The event name. + * @returns {Array} The registered listeners. + * @public + */ + EventEmitter.prototype.listeners = function listeners(event) { + var evt = prefix ? prefix + event : event + , handlers = this._events[evt]; + + if (!handlers) return []; + if (handlers.fn) return [handlers.fn]; + + for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { + ee[i] = handlers[i].fn; + } + + return ee; + }; + + /** + * Return the number of listeners listening to a given event. + * + * @param {(String|Symbol)} event The event name. + * @returns {Number} The number of listeners. + * @public + */ + EventEmitter.prototype.listenerCount = function listenerCount(event) { + var evt = prefix ? prefix + event : event + , listeners = this._events[evt]; + + if (!listeners) return 0; + if (listeners.fn) return 1; + return listeners.length; + }; + + /** + * Calls each of the listeners registered for a given event. + * + * @param {(String|Symbol)} event The event name. + * @returns {Boolean} `true` if the event had listeners, else `false`. + * @public + */ + EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { + var evt = prefix ? prefix + event : event; + + if (!this._events[evt]) return false; + + var listeners = this._events[evt] + , len = arguments.length + , args + , i; + + if (listeners.fn) { + if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); + + switch (len) { + case 1: return listeners.fn.call(listeners.context), true; + case 2: return listeners.fn.call(listeners.context, a1), true; + case 3: return listeners.fn.call(listeners.context, a1, a2), true; + case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; + case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; + case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; + } + + for (i = 1, args = new Array(len -1); i < len; i++) { + args[i - 1] = arguments[i]; + } + + listeners.fn.apply(listeners.context, args); + } else { + var length = listeners.length + , j; + + for (i = 0; i < length; i++) { + if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); + + switch (len) { + case 1: listeners[i].fn.call(listeners[i].context); break; + case 2: listeners[i].fn.call(listeners[i].context, a1); break; + case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; + case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; + default: + if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { + args[j - 1] = arguments[j]; + } + + listeners[i].fn.apply(listeners[i].context, args); + } + } + } + + return true; + }; + + /** + * Add a listener for a given event. + * + * @param {(String|Symbol)} event The event name. + * @param {Function} fn The listener function. + * @param {*} [context=this] The context to invoke the listener with. + * @returns {EventEmitter} `this`. + * @public + */ + EventEmitter.prototype.on = function on(event, fn, context) { + return addListener(this, event, fn, context, false); + }; + + /** + * Add a one-time listener for a given event. + * + * @param {(String|Symbol)} event The event name. + * @param {Function} fn The listener function. + * @param {*} [context=this] The context to invoke the listener with. + * @returns {EventEmitter} `this`. + * @public + */ + EventEmitter.prototype.once = function once(event, fn, context) { + return addListener(this, event, fn, context, true); + }; + + /** + * Remove the listeners of a given event. + * + * @param {(String|Symbol)} event The event name. + * @param {Function} fn Only remove the listeners that match this function. + * @param {*} context Only remove the listeners that have this context. + * @param {Boolean} once Only remove one-time listeners. + * @returns {EventEmitter} `this`. + * @public + */ + EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { + var evt = prefix ? prefix + event : event; + + if (!this._events[evt]) return this; + if (!fn) { + clearEvent(this, evt); + return this; + } + + var listeners = this._events[evt]; + + if (listeners.fn) { + if ( + listeners.fn === fn && + (!once || listeners.once) && + (!context || listeners.context === context) + ) { + clearEvent(this, evt); + } + } else { + for (var i = 0, events = [], length = listeners.length; i < length; i++) { + if ( + listeners[i].fn !== fn || + (once && !listeners[i].once) || + (context && listeners[i].context !== context) + ) { + events.push(listeners[i]); + } + } + + // + // Reset the array, or remove it completely if we have no more listeners. + // + if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; + else clearEvent(this, evt); + } + + return this; + }; + + /** + * Remove all listeners, or those of the specified event. + * + * @param {(String|Symbol)} [event] The event name. + * @returns {EventEmitter} `this`. + * @public + */ + EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { + var evt; + + if (event) { + evt = prefix ? prefix + event : event; + if (this._events[evt]) clearEvent(this, evt); + } else { + this._events = new Events(); + this._eventsCount = 0; + } + + return this; + }; + + // + // Alias methods names because people roll like that. + // + EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + // + // Expose the prefix. + // + EventEmitter.prefixed = prefix; + + // + // Allow `EventEmitter` to be imported as module namespace. + // + EventEmitter.EventEmitter = EventEmitter; + + // + // Expose the module. + // + if ('undefined' !== 'object') { + module.exports = EventEmitter; + } + } (eventemitter3$1)); + + var eventemitter3Exports = eventemitter3$1.exports; + var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports); + + var r={grad:.9,turn:360,rad:360/(2*Math.PI)},t=function(r){return "string"==typeof r?r.length>0:"number"==typeof r},n=function(r,t,n){return void 0===t&&(t=0),void 0===n&&(n=Math.pow(10,t)),Math.round(n*r)/n+0},e=function(r,t,n){return void 0===t&&(t=0),void 0===n&&(n=1),r>n?n:r>t?r:t},u=function(r){return (r=isFinite(r)?r%360:0)>0?r:r+360},a=function(r){return {r:e(r.r,0,255),g:e(r.g,0,255),b:e(r.b,0,255),a:e(r.a)}},o=function(r){return {r:n(r.r),g:n(r.g),b:n(r.b),a:n(r.a,3)}},i=/^#([0-9a-f]{3,8})$/i,s=function(r){var t=r.toString(16);return t.length<2?"0"+t:t},h=function(r){var t=r.r,n=r.g,e=r.b,u=r.a,a=Math.max(t,n,e),o=a-Math.min(t,n,e),i=o?a===t?(n-e)/o:a===n?2+(e-t)/o:4+(t-n)/o:0;return {h:60*(i<0?i+6:i),s:a?o/a*100:0,v:a/255*100,a:u}},b=function(r){var t=r.h,n=r.s,e=r.v,u=r.a;t=t/360*6,n/=100,e/=100;var a=Math.floor(t),o=e*(1-n),i=e*(1-(t-a)*n),s=e*(1-(1-t+a)*n),h=a%6;return {r:255*[e,i,o,o,s,e][h],g:255*[s,e,e,i,o,o][h],b:255*[o,o,s,e,e,i][h],a:u}},g=function(r){return {h:u(r.h),s:e(r.s,0,100),l:e(r.l,0,100),a:e(r.a)}},d=function(r){return {h:n(r.h),s:n(r.s),l:n(r.l),a:n(r.a,3)}},f=function(r){return b((n=(t=r).s,{h:t.h,s:(n*=((e=t.l)<50?e:100-e)/100)>0?2*n/(e+n)*100:0,v:e+n,a:t.a}));var t,n,e;},c=function(r){return {h:(t=h(r)).h,s:(u=(200-(n=t.s))*(e=t.v)/100)>0&&u<200?n*e/100/(u<=100?u:200-u)*100:0,l:u/2,a:t.a};var t,n,e,u;},l=/^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s*,\s*([+-]?\d*\.?\d+)%\s*,\s*([+-]?\d*\.?\d+)%\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i,p=/^hsla?\(\s*([+-]?\d*\.?\d+)(deg|rad|grad|turn)?\s+([+-]?\d*\.?\d+)%\s+([+-]?\d*\.?\d+)%\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i,v=/^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*,\s*([+-]?\d*\.?\d+)(%)?\s*(?:,\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i,m=/^rgba?\(\s*([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s+([+-]?\d*\.?\d+)(%)?\s*(?:\/\s*([+-]?\d*\.?\d+)(%)?\s*)?\)$/i,y={string:[[function(r){var t=i.exec(r);return t?(r=t[1]).length<=4?{r:parseInt(r[0]+r[0],16),g:parseInt(r[1]+r[1],16),b:parseInt(r[2]+r[2],16),a:4===r.length?n(parseInt(r[3]+r[3],16)/255,2):1}:6===r.length||8===r.length?{r:parseInt(r.substr(0,2),16),g:parseInt(r.substr(2,2),16),b:parseInt(r.substr(4,2),16),a:8===r.length?n(parseInt(r.substr(6,2),16)/255,2):1}:null:null},"hex"],[function(r){var t=v.exec(r)||m.exec(r);return t?t[2]!==t[4]||t[4]!==t[6]?null:a({r:Number(t[1])/(t[2]?100/255:1),g:Number(t[3])/(t[4]?100/255:1),b:Number(t[5])/(t[6]?100/255:1),a:void 0===t[7]?1:Number(t[7])/(t[8]?100:1)}):null},"rgb"],[function(t){var n=l.exec(t)||p.exec(t);if(!n)return null;var e,u,a=g({h:(e=n[1],u=n[2],void 0===u&&(u="deg"),Number(e)*(r[u]||1)),s:Number(n[3]),l:Number(n[4]),a:void 0===n[5]?1:Number(n[5])/(n[6]?100:1)});return f(a)},"hsl"]],object:[[function(r){var n=r.r,e=r.g,u=r.b,o=r.a,i=void 0===o?1:o;return t(n)&&t(e)&&t(u)?a({r:Number(n),g:Number(e),b:Number(u),a:Number(i)}):null},"rgb"],[function(r){var n=r.h,e=r.s,u=r.l,a=r.a,o=void 0===a?1:a;if(!t(n)||!t(e)||!t(u))return null;var i=g({h:Number(n),s:Number(e),l:Number(u),a:Number(o)});return f(i)},"hsl"],[function(r){var n=r.h,a=r.s,o=r.v,i=r.a,s=void 0===i?1:i;if(!t(n)||!t(a)||!t(o))return null;var h=function(r){return {h:u(r.h),s:e(r.s,0,100),v:e(r.v,0,100),a:e(r.a)}}({h:Number(n),s:Number(a),v:Number(o),a:Number(s)});return b(h)},"hsv"]]},N=function(r,t){for(var n=0;n=.5},r.prototype.toHex=function(){return r=o(this.rgba),t=r.r,e=r.g,u=r.b,i=(a=r.a)<1?s(n(255*a)):"","#"+s(t)+s(e)+s(u)+i;var r,t,e,u,a,i;},r.prototype.toRgb=function(){return o(this.rgba)},r.prototype.toRgbString=function(){return r=o(this.rgba),t=r.r,n=r.g,e=r.b,(u=r.a)<1?"rgba("+t+", "+n+", "+e+", "+u+")":"rgb("+t+", "+n+", "+e+")";var r,t,n,e,u;},r.prototype.toHsl=function(){return d(c(this.rgba))},r.prototype.toHslString=function(){return r=d(c(this.rgba)),t=r.h,n=r.s,e=r.l,(u=r.a)<1?"hsla("+t+", "+n+"%, "+e+"%, "+u+")":"hsl("+t+", "+n+"%, "+e+"%)";var r,t,n,e,u;},r.prototype.toHsv=function(){return r=h(this.rgba),{h:n(r.h),s:n(r.s),v:n(r.v),a:n(r.a,3)};var r;},r.prototype.invert=function(){return w({r:255-(r=this.rgba).r,g:255-r.g,b:255-r.b,a:r.a});var r;},r.prototype.saturate=function(r){return void 0===r&&(r=.1),w(M(this.rgba,r))},r.prototype.desaturate=function(r){return void 0===r&&(r=.1),w(M(this.rgba,-r))},r.prototype.grayscale=function(){return w(M(this.rgba,-1))},r.prototype.lighten=function(r){return void 0===r&&(r=.1),w($(this.rgba,r))},r.prototype.darken=function(r){return void 0===r&&(r=.1),w($(this.rgba,-r))},r.prototype.rotate=function(r){return void 0===r&&(r=15),this.hue(this.hue()+r)},r.prototype.alpha=function(r){return "number"==typeof r?w({r:(t=this.rgba).r,g:t.g,b:t.b,a:r}):n(this.rgba.a,3);var t;},r.prototype.hue=function(r){var t=c(this.rgba);return "number"==typeof r?w({h:r,s:t.s,l:t.l,a:t.a}):n(t.h)},r.prototype.isEqual=function(r){return this.toHex()===w(r).toHex()},r}(),w=function(r){return r instanceof j?r:new j(r)},S=[],k=function(r){r.forEach(function(r){S.indexOf(r)<0&&(r(j,y),S.push(r));});},E=function(){return new j({r:255*Math.random(),g:255*Math.random(),b:255*Math.random()})}; + + function namesPlugin(e,f){var a={white:"#ffffff",bisque:"#ffe4c4",blue:"#0000ff",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",antiquewhite:"#faebd7",aqua:"#00ffff",azure:"#f0ffff",whitesmoke:"#f5f5f5",papayawhip:"#ffefd5",plum:"#dda0dd",blanchedalmond:"#ffebcd",black:"#000000",gold:"#ffd700",goldenrod:"#daa520",gainsboro:"#dcdcdc",cornsilk:"#fff8dc",cornflowerblue:"#6495ed",burlywood:"#deb887",aquamarine:"#7fffd4",beige:"#f5f5dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkkhaki:"#bdb76b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",peachpuff:"#ffdab9",darkmagenta:"#8b008b",darkred:"#8b0000",darkorchid:"#9932cc",darkorange:"#ff8c00",darkslateblue:"#483d8b",gray:"#808080",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",deeppink:"#ff1493",deepskyblue:"#00bfff",wheat:"#f5deb3",firebrick:"#b22222",floralwhite:"#fffaf0",ghostwhite:"#f8f8ff",darkviolet:"#9400d3",magenta:"#ff00ff",green:"#008000",dodgerblue:"#1e90ff",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",blueviolet:"#8a2be2",forestgreen:"#228b22",lawngreen:"#7cfc00",indianred:"#cd5c5c",indigo:"#4b0082",fuchsia:"#ff00ff",brown:"#a52a2a",maroon:"#800000",mediumblue:"#0000cd",lightcoral:"#f08080",darkturquoise:"#00ced1",lightcyan:"#e0ffff",ivory:"#fffff0",lightyellow:"#ffffe0",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",linen:"#faf0e6",mediumaquamarine:"#66cdaa",lemonchiffon:"#fffacd",lime:"#00ff00",khaki:"#f0e68c",mediumseagreen:"#3cb371",limegreen:"#32cd32",mediumspringgreen:"#00fa9a",lightskyblue:"#87cefa",lightblue:"#add8e6",midnightblue:"#191970",lightpink:"#ffb6c1",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",mintcream:"#f5fffa",lightslategray:"#778899",lightslategrey:"#778899",navajowhite:"#ffdead",navy:"#000080",mediumvioletred:"#c71585",powderblue:"#b0e0e6",palegoldenrod:"#eee8aa",oldlace:"#fdf5e6",paleturquoise:"#afeeee",mediumturquoise:"#48d1cc",mediumorchid:"#ba55d3",rebeccapurple:"#663399",lightsteelblue:"#b0c4de",mediumslateblue:"#7b68ee",thistle:"#d8bfd8",tan:"#d2b48c",orchid:"#da70d6",mediumpurple:"#9370db",purple:"#800080",pink:"#ffc0cb",skyblue:"#87ceeb",springgreen:"#00ff7f",palegreen:"#98fb98",red:"#ff0000",yellow:"#ffff00",slateblue:"#6a5acd",lavenderblush:"#fff0f5",peru:"#cd853f",palevioletred:"#db7093",violet:"#ee82ee",teal:"#008080",slategray:"#708090",slategrey:"#708090",aliceblue:"#f0f8ff",darkseagreen:"#8fbc8f",darkolivegreen:"#556b2f",greenyellow:"#adff2f",seagreen:"#2e8b57",seashell:"#fff5ee",tomato:"#ff6347",silver:"#c0c0c0",sienna:"#a0522d",lavender:"#e6e6fa",lightgreen:"#90ee90",orange:"#ffa500",orangered:"#ff4500",steelblue:"#4682b4",royalblue:"#4169e1",turquoise:"#40e0d0",yellowgreen:"#9acd32",salmon:"#fa8072",saddlebrown:"#8b4513",sandybrown:"#f4a460",rosybrown:"#bc8f8f",darksalmon:"#e9967a",lightgoldenrodyellow:"#fafad2",snow:"#fffafa",lightgrey:"#d3d3d3",lightgray:"#d3d3d3",dimgray:"#696969",dimgrey:"#696969",olivedrab:"#6b8e23",olive:"#808000"},r={};for(var d in a)r[a[d]]=d;var l={};e.prototype.toName=function(f){if(!(this.rgba.a||this.rgba.r||this.rgba.g||this.rgba.b))return "transparent";var d,i,n=r[this.toHex()];if(n)return n;if(null==f?void 0:f.closest){var o=this.toRgb(),t=1/0,b="black";if(!l.length)for(var c in a)l[c]=new e(a[c]).toRgb();for(var g in a){var u=(d=o,i=l[g],Math.pow(d.r-i.r,2)+Math.pow(d.g-i.g,2)+Math.pow(d.b-i.b,2));u key in obj ? __defProp$10(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$10 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$10.call(b, prop)) + __defNormalProp$10(a, prop, b[prop]); + if (__getOwnPropSymbols$10) + for (var prop of __getOwnPropSymbols$10(b)) { + if (__propIsEnum$10.call(b, prop)) + __defNormalProp$10(a, prop, b[prop]); + } + return a; + }; + k([namesPlugin]); + const _Color = class _Color { + /** + * @param {ColorSource} value - Optional value to use, if not provided, white is used. + */ + constructor(value = 16777215) { + this._value = null; + this._components = new Float32Array(4); + this._components.fill(1); + this._int = 16777215; + this.value = value; + } + /** Get red component (0 - 1) */ + get red() { + return this._components[0]; + } + /** Get green component (0 - 1) */ + get green() { + return this._components[1]; + } + /** Get blue component (0 - 1) */ + get blue() { + return this._components[2]; + } + /** Get alpha component (0 - 1) */ + get alpha() { + return this._components[3]; + } + /** + * Set the value, suitable for chaining + * @param value + * @see Color.value + */ + setValue(value) { + this.value = value; + return this; + } + /** + * The current color source. + * + * When setting: + * - Setting to an instance of `Color` will copy its color source and components. + * - Otherwise, `Color` will try to normalize the color source and set the components. + * If the color source is invalid, an `Error` will be thrown and the `Color` will left unchanged. + * + * Note: The `null` in the setter's parameter type is added to match the TypeScript rule: return type of getter + * must be assignable to its setter's parameter type. Setting `value` to `null` will throw an `Error`. + * + * When getting: + * - A return value of `null` means the previous value was overridden (e.g., {@link Color.multiply multiply}, + * {@link Color.premultiply premultiply} or {@link Color.round round}). + * - Otherwise, the color source used when setting is returned. + */ + set value(value) { + if (value instanceof _Color) { + this._value = this._cloneSource(value._value); + this._int = value._int; + this._components.set(value._components); + } else if (value === null) { + throw new Error("Cannot set Color#value to null"); + } else if (this._value === null || !this._isSourceEqual(this._value, value)) { + this._normalize(value); + this._value = this._cloneSource(value); + } + } + get value() { + return this._value; + } + /** + * Copy a color source internally. + * @param value - Color source + */ + _cloneSource(value) { + if (typeof value === "string" || typeof value === "number" || value instanceof Number || value === null) { + return value; + } else if (Array.isArray(value) || ArrayBuffer.isView(value)) { + return value.slice(0); + } else if (typeof value === "object" && value !== null) { + return __spreadValues$10({}, value); + } + return value; + } + /** + * Equality check for color sources. + * @param value1 - First color source + * @param value2 - Second color source + * @returns `true` if the color sources are equal, `false` otherwise. + */ + _isSourceEqual(value1, value2) { + const type1 = typeof value1; + const type2 = typeof value2; + if (type1 !== type2) { + return false; + } else if (type1 === "number" || type1 === "string" || value1 instanceof Number) { + return value1 === value2; + } else if (Array.isArray(value1) && Array.isArray(value2) || ArrayBuffer.isView(value1) && ArrayBuffer.isView(value2)) { + if (value1.length !== value2.length) { + return false; + } + return value1.every((v, i) => v === value2[i]); + } else if (value1 !== null && value2 !== null) { + const keys1 = Object.keys(value1); + const keys2 = Object.keys(value2); + if (keys1.length !== keys2.length) { + return false; + } + return keys1.every((key) => value1[key] === value2[key]); + } + return value1 === value2; + } + /** + * Convert to a RGBA color object. + * @example + * import { Color } from 'pixi.js'; + * new Color('white').toRgb(); // returns { r: 1, g: 1, b: 1, a: 1 } + */ + toRgba() { + const [r, g, b, a] = this._components; + return { r, g, b, a }; + } + /** + * Convert to a RGB color object. + * @example + * import { Color } from 'pixi.js'; + * new Color('white').toRgb(); // returns { r: 1, g: 1, b: 1 } + */ + toRgb() { + const [r, g, b] = this._components; + return { r, g, b }; + } + /** Convert to a CSS-style rgba string: `rgba(255,255,255,1.0)`. */ + toRgbaString() { + const [r, g, b] = this.toUint8RgbArray(); + return `rgba(${r},${g},${b},${this.alpha})`; + } + toUint8RgbArray(out) { + const [r, g, b] = this._components; + if (!this._arrayRgb) { + this._arrayRgb = []; + } + out = out || this._arrayRgb; + out[0] = Math.round(r * 255); + out[1] = Math.round(g * 255); + out[2] = Math.round(b * 255); + return out; + } + toArray(out) { + if (!this._arrayRgba) { + this._arrayRgba = []; + } + out = out || this._arrayRgba; + const [r, g, b, a] = this._components; + out[0] = r; + out[1] = g; + out[2] = b; + out[3] = a; + return out; + } + toRgbArray(out) { + if (!this._arrayRgb) { + this._arrayRgb = []; + } + out = out || this._arrayRgb; + const [r, g, b] = this._components; + out[0] = r; + out[1] = g; + out[2] = b; + return out; + } + /** + * Convert to a hexadecimal number. + * @example + * import { Color } from 'pixi.js'; + * new Color('white').toNumber(); // returns 16777215 + */ + toNumber() { + return this._int; + } + /** + * Convert to a BGR number + * @example + * import { Color } from 'pixi.js'; + * new Color(0xffcc99).toBgrNumber(); // returns 0x99ccff + */ + toBgrNumber() { + const [r, g, b] = this.toUint8RgbArray(); + return (b << 16) + (g << 8) + r; + } + /** + * Convert to a hexadecimal number in little endian format (e.g., BBGGRR). + * @example + * import { Color } from 'pixi.js'; + * new Color(0xffcc99).toLittleEndianNumber(); // returns 0x99ccff + * @returns {number} - The color as a number in little endian format. + */ + toLittleEndianNumber() { + const value = this._int; + return (value >> 16) + (value & 65280) + ((value & 255) << 16); + } + /** + * Multiply with another color. This action is destructive, and will + * override the previous `value` property to be `null`. + * @param {ColorSource} value - The color to multiply by. + */ + multiply(value) { + const [r, g, b, a] = _Color._temp.setValue(value)._components; + this._components[0] *= r; + this._components[1] *= g; + this._components[2] *= b; + this._components[3] *= a; + this._refreshInt(); + this._value = null; + return this; + } + /** + * Converts color to a premultiplied alpha format. This action is destructive, and will + * override the previous `value` property to be `null`. + * @param alpha - The alpha to multiply by. + * @param {boolean} [applyToRGB=true] - Whether to premultiply RGB channels. + * @returns {Color} - Itself. + */ + premultiply(alpha, applyToRGB = true) { + if (applyToRGB) { + this._components[0] *= alpha; + this._components[1] *= alpha; + this._components[2] *= alpha; + } + this._components[3] = alpha; + this._refreshInt(); + this._value = null; + return this; + } + /** + * Premultiplies alpha with current color. + * @param {number} alpha - The alpha to multiply by. + * @param {boolean} [applyToRGB=true] - Whether to premultiply RGB channels. + * @returns {number} tint multiplied by alpha + */ + toPremultiplied(alpha, applyToRGB = true) { + if (alpha === 1) { + return (255 << 24) + this._int; + } + if (alpha === 0) { + return applyToRGB ? 0 : this._int; + } + let r = this._int >> 16 & 255; + let g = this._int >> 8 & 255; + let b = this._int & 255; + if (applyToRGB) { + r = r * alpha + 0.5 | 0; + g = g * alpha + 0.5 | 0; + b = b * alpha + 0.5 | 0; + } + return (alpha * 255 << 24) + (r << 16) + (g << 8) + b; + } + /** + * Convert to a hexidecimal string. + * @example + * import { Color } from 'pixi.js'; + * new Color('white').toHex(); // returns "#ffffff" + */ + toHex() { + const hexString = this._int.toString(16); + return `#${"000000".substring(0, 6 - hexString.length) + hexString}`; + } + /** + * Convert to a hexidecimal string with alpha. + * @example + * import { Color } from 'pixi.js'; + * new Color('white').toHexa(); // returns "#ffffffff" + */ + toHexa() { + const alphaValue = Math.round(this._components[3] * 255); + const alphaString = alphaValue.toString(16); + return this.toHex() + "00".substring(0, 2 - alphaString.length) + alphaString; + } + /** + * Set alpha, suitable for chaining. + * @param alpha + */ + setAlpha(alpha) { + this._components[3] = this._clamp(alpha); + return this; + } + /** + * Normalize the input value into rgba + * @param value - Input value + */ + _normalize(value) { + let r; + let g; + let b; + let a; + if ((typeof value === "number" || value instanceof Number) && value >= 0 && value <= 16777215) { + const int = value; + r = (int >> 16 & 255) / 255; + g = (int >> 8 & 255) / 255; + b = (int & 255) / 255; + a = 1; + } else if ((Array.isArray(value) || value instanceof Float32Array) && value.length >= 3 && value.length <= 4) { + value = this._clamp(value); + [r, g, b, a = 1] = value; + } else if ((value instanceof Uint8Array || value instanceof Uint8ClampedArray) && value.length >= 3 && value.length <= 4) { + value = this._clamp(value, 0, 255); + [r, g, b, a = 255] = value; + r /= 255; + g /= 255; + b /= 255; + a /= 255; + } else if (typeof value === "string" || typeof value === "object") { + if (typeof value === "string") { + const match = _Color.HEX_PATTERN.exec(value); + if (match) { + value = `#${match[2]}`; + } + } + const color = w(value); + if (color.isValid()) { + ({ r, g, b, a } = color.rgba); + r /= 255; + g /= 255; + b /= 255; + } + } + if (r !== void 0) { + this._components[0] = r; + this._components[1] = g; + this._components[2] = b; + this._components[3] = a; + this._refreshInt(); + } else { + throw new Error(`Unable to convert color ${value}`); + } + } + /** Refresh the internal color rgb number */ + _refreshInt() { + this._clamp(this._components); + const [r, g, b] = this._components; + this._int = (r * 255 << 16) + (g * 255 << 8) + (b * 255 | 0); + } + /** + * Clamps values to a range. Will override original values + * @param value - Value(s) to clamp + * @param min - Minimum value + * @param max - Maximum value + */ + _clamp(value, min = 0, max = 1) { + if (typeof value === "number") { + return Math.min(Math.max(value, min), max); + } + value.forEach((v, i) => { + value[i] = Math.min(Math.max(v, min), max); + }); + return value; + } + /** + * Check if the value is a color-like object + * @param value - Value to check + * @returns True if the value is a color-like object + * @static + * @example + * import { Color } from 'pixi.js'; + * Color.isColorLike('white'); // returns true + * Color.isColorLike(0xffffff); // returns true + * Color.isColorLike([1, 1, 1]); // returns true + */ + static isColorLike(value) { + return typeof value === "number" || typeof value === "string" || value instanceof Number || value instanceof _Color || Array.isArray(value) || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Float32Array || value.r !== void 0 && value.g !== void 0 && value.b !== void 0 || value.r !== void 0 && value.g !== void 0 && value.b !== void 0 && value.a !== void 0 || value.h !== void 0 && value.s !== void 0 && value.l !== void 0 || value.h !== void 0 && value.s !== void 0 && value.l !== void 0 && value.a !== void 0 || value.h !== void 0 && value.s !== void 0 && value.v !== void 0 || value.h !== void 0 && value.s !== void 0 && value.v !== void 0 && value.a !== void 0; + } + }; + /** + * Default Color object for static uses + * @example + * import { Color } from 'pixi.js'; + * Color.shared.setValue(0xffffff).toHex(); // '#ffffff' + */ + _Color.shared = new _Color(); + /** + * Temporary Color object for static uses internally. + * As to not conflict with Color.shared. + * @ignore + */ + _Color._temp = new _Color(); + /** Pattern for hex strings */ + // eslint-disable-next-line @typescript-eslint/naming-convention + _Color.HEX_PATTERN = /^(#|0x)?(([a-f0-9]{3}){1,2}([a-f0-9]{2})?)$/i; + let Color = _Color; + + "use strict"; + const cullingMixin = { + cullArea: null, + cullable: false, + cullableChildren: true + }; + + "use strict"; + const PI_2 = Math.PI * 2; + const RAD_TO_DEG = 180 / Math.PI; + const DEG_TO_RAD = Math.PI / 180; + + "use strict"; + class Point { + /** + * Creates a new `Point` + * @param {number} [x=0] - position of the point on the x axis + * @param {number} [y=0] - position of the point on the y axis + */ + constructor(x = 0, y = 0) { + /** Position of the point on the x axis */ + this.x = 0; + /** Position of the point on the y axis */ + this.y = 0; + this.x = x; + this.y = y; + } + /** + * Creates a clone of this point + * @returns A clone of this point + */ + clone() { + return new Point(this.x, this.y); + } + /** + * Copies `x` and `y` from the given point into this point + * @param p - The point to copy from + * @returns The point instance itself + */ + copyFrom(p) { + this.set(p.x, p.y); + return this; + } + /** + * Copies this point's x and y into the given point (`p`). + * @param p - The point to copy to. Can be any of type that is or extends `PointData` + * @returns The point (`p`) with values updated + */ + copyTo(p) { + p.set(this.x, this.y); + return p; + } + /** + * Accepts another point (`p`) and returns `true` if the given point is equal to this point + * @param p - The point to check + * @returns Returns `true` if both `x` and `y` are equal + */ + equals(p) { + return p.x === this.x && p.y === this.y; + } + /** + * Sets the point to a new `x` and `y` position. + * If `y` is omitted, both `x` and `y` will be set to `x`. + * @param {number} [x=0] - position of the point on the `x` axis + * @param {number} [y=x] - position of the point on the `y` axis + * @returns The point instance itself + */ + set(x = 0, y = x) { + this.x = x; + this.y = y; + return this; + } + toString() { + return `[pixi.js/math:Point x=${this.x} y=${this.y}]`; + } + /** + * A static Point object with `x` and `y` values of `0`. Can be used to avoid creating new objects multiple times. + * @readonly + */ + static get shared() { + tempPoint.x = 0; + tempPoint.y = 0; + return tempPoint; + } + } + const tempPoint = new Point(); + + "use strict"; + class Matrix { + /** + * @param a - x scale + * @param b - y skew + * @param c - x skew + * @param d - y scale + * @param tx - x translation + * @param ty - y translation + */ + constructor(a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0) { + /** An array of the current matrix. Only populated when `toArray` is called */ + this.array = null; + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + } + /** + * Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows: + * + * a = array[0] + * b = array[1] + * c = array[3] + * d = array[4] + * tx = array[2] + * ty = array[5] + * @param array - The array that the matrix will be populated from. + */ + fromArray(array) { + this.a = array[0]; + this.b = array[1]; + this.c = array[3]; + this.d = array[4]; + this.tx = array[2]; + this.ty = array[5]; + } + /** + * Sets the matrix properties. + * @param a - Matrix component + * @param b - Matrix component + * @param c - Matrix component + * @param d - Matrix component + * @param tx - Matrix component + * @param ty - Matrix component + * @returns This matrix. Good for chaining method calls. + */ + set(a, b, c, d, tx, ty) { + this.a = a; + this.b = b; + this.c = c; + this.d = d; + this.tx = tx; + this.ty = ty; + return this; + } + /** + * Creates an array from the current Matrix object. + * @param transpose - Whether we need to transpose the matrix or not + * @param [out=new Float32Array(9)] - If provided the array will be assigned to out + * @returns The newly created array which contains the matrix + */ + toArray(transpose, out) { + if (!this.array) { + this.array = new Float32Array(9); + } + const array = out || this.array; + if (transpose) { + array[0] = this.a; + array[1] = this.b; + array[2] = 0; + array[3] = this.c; + array[4] = this.d; + array[5] = 0; + array[6] = this.tx; + array[7] = this.ty; + array[8] = 1; + } else { + array[0] = this.a; + array[1] = this.c; + array[2] = this.tx; + array[3] = this.b; + array[4] = this.d; + array[5] = this.ty; + array[6] = 0; + array[7] = 0; + array[8] = 1; + } + return array; + } + /** + * Get a new position with the current transformation applied. + * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) + * @param pos - The origin + * @param {Point} [newPos] - The point that the new position is assigned to (allowed to be same as input) + * @returns {Point} The new point, transformed through this matrix + */ + apply(pos, newPos) { + newPos = newPos || new Point(); + const x = pos.x; + const y = pos.y; + newPos.x = this.a * x + this.c * y + this.tx; + newPos.y = this.b * x + this.d * y + this.ty; + return newPos; + } + /** + * Get a new position with the inverse of the current transformation applied. + * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) + * @param pos - The origin + * @param {Point} [newPos] - The point that the new position is assigned to (allowed to be same as input) + * @returns {Point} The new point, inverse-transformed through this matrix + */ + applyInverse(pos, newPos) { + newPos = newPos || new Point(); + const a = this.a; + const b = this.b; + const c = this.c; + const d = this.d; + const tx = this.tx; + const ty = this.ty; + const id = 1 / (a * d + c * -b); + const x = pos.x; + const y = pos.y; + newPos.x = d * id * x + -c * id * y + (ty * c - tx * d) * id; + newPos.y = a * id * y + -b * id * x + (-ty * a + tx * b) * id; + return newPos; + } + /** + * Translates the matrix on the x and y. + * @param x - How much to translate x by + * @param y - How much to translate y by + * @returns This matrix. Good for chaining method calls. + */ + translate(x, y) { + this.tx += x; + this.ty += y; + return this; + } + /** + * Applies a scale transformation to the matrix. + * @param x - The amount to scale horizontally + * @param y - The amount to scale vertically + * @returns This matrix. Good for chaining method calls. + */ + scale(x, y) { + this.a *= x; + this.d *= y; + this.c *= x; + this.b *= y; + this.tx *= x; + this.ty *= y; + return this; + } + /** + * Applies a rotation transformation to the matrix. + * @param angle - The angle in radians. + * @returns This matrix. Good for chaining method calls. + */ + rotate(angle) { + const cos = Math.cos(angle); + const sin = Math.sin(angle); + const a1 = this.a; + const c1 = this.c; + const tx1 = this.tx; + this.a = a1 * cos - this.b * sin; + this.b = a1 * sin + this.b * cos; + this.c = c1 * cos - this.d * sin; + this.d = c1 * sin + this.d * cos; + this.tx = tx1 * cos - this.ty * sin; + this.ty = tx1 * sin + this.ty * cos; + return this; + } + /** + * Appends the given Matrix to this Matrix. + * @param matrix - The matrix to append. + * @returns This matrix. Good for chaining method calls. + */ + append(matrix) { + const a1 = this.a; + const b1 = this.b; + const c1 = this.c; + const d1 = this.d; + this.a = matrix.a * a1 + matrix.b * c1; + this.b = matrix.a * b1 + matrix.b * d1; + this.c = matrix.c * a1 + matrix.d * c1; + this.d = matrix.c * b1 + matrix.d * d1; + this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; + this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; + return this; + } + /** + * Appends two matrix's and sets the result to this matrix. AB = A * B + * @param a - The matrix to append. + * @param b - The matrix to append. + * @returns This matrix. Good for chaining method calls. + */ + appendFrom(a, b) { + const a1 = a.a; + const b1 = a.b; + const c1 = a.c; + const d1 = a.d; + const tx = a.tx; + const ty = a.ty; + const a2 = b.a; + const b2 = b.b; + const c2 = b.c; + const d2 = b.d; + this.a = a1 * a2 + b1 * c2; + this.b = a1 * b2 + b1 * d2; + this.c = c1 * a2 + d1 * c2; + this.d = c1 * b2 + d1 * d2; + this.tx = tx * a2 + ty * c2 + b.tx; + this.ty = tx * b2 + ty * d2 + b.ty; + return this; + } + /** + * Sets the matrix based on all the available properties + * @param x - Position on the x axis + * @param y - Position on the y axis + * @param pivotX - Pivot on the x axis + * @param pivotY - Pivot on the y axis + * @param scaleX - Scale on the x axis + * @param scaleY - Scale on the y axis + * @param rotation - Rotation in radians + * @param skewX - Skew on the x axis + * @param skewY - Skew on the y axis + * @returns This matrix. Good for chaining method calls. + */ + setTransform(x, y, pivotX, pivotY, scaleX, scaleY, rotation, skewX, skewY) { + this.a = Math.cos(rotation + skewY) * scaleX; + this.b = Math.sin(rotation + skewY) * scaleX; + this.c = -Math.sin(rotation - skewX) * scaleY; + this.d = Math.cos(rotation - skewX) * scaleY; + this.tx = x - (pivotX * this.a + pivotY * this.c); + this.ty = y - (pivotX * this.b + pivotY * this.d); + return this; + } + /** + * Prepends the given Matrix to this Matrix. + * @param matrix - The matrix to prepend + * @returns This matrix. Good for chaining method calls. + */ + prepend(matrix) { + const tx1 = this.tx; + if (matrix.a !== 1 || matrix.b !== 0 || matrix.c !== 0 || matrix.d !== 1) { + const a1 = this.a; + const c1 = this.c; + this.a = a1 * matrix.a + this.b * matrix.c; + this.b = a1 * matrix.b + this.b * matrix.d; + this.c = c1 * matrix.a + this.d * matrix.c; + this.d = c1 * matrix.b + this.d * matrix.d; + } + this.tx = tx1 * matrix.a + this.ty * matrix.c + matrix.tx; + this.ty = tx1 * matrix.b + this.ty * matrix.d + matrix.ty; + return this; + } + /** + * Decomposes the matrix (x, y, scaleX, scaleY, and rotation) and sets the properties on to a transform. + * @param transform - The transform to apply the properties to. + * @returns The transform with the newly applied properties + */ + decompose(transform) { + const a = this.a; + const b = this.b; + const c = this.c; + const d = this.d; + const pivot = transform.pivot; + const skewX = -Math.atan2(-c, d); + const skewY = Math.atan2(b, a); + const delta = Math.abs(skewX + skewY); + if (delta < 1e-5 || Math.abs(PI_2 - delta) < 1e-5) { + transform.rotation = skewY; + transform.skew.x = transform.skew.y = 0; + } else { + transform.rotation = 0; + transform.skew.x = skewX; + transform.skew.y = skewY; + } + transform.scale.x = Math.sqrt(a * a + b * b); + transform.scale.y = Math.sqrt(c * c + d * d); + transform.position.x = this.tx + (pivot.x * a + pivot.y * c); + transform.position.y = this.ty + (pivot.x * b + pivot.y * d); + return transform; + } + /** + * Inverts this matrix + * @returns This matrix. Good for chaining method calls. + */ + invert() { + const a1 = this.a; + const b1 = this.b; + const c1 = this.c; + const d1 = this.d; + const tx1 = this.tx; + const n = a1 * d1 - b1 * c1; + this.a = d1 / n; + this.b = -b1 / n; + this.c = -c1 / n; + this.d = a1 / n; + this.tx = (c1 * this.ty - d1 * tx1) / n; + this.ty = -(a1 * this.ty - b1 * tx1) / n; + return this; + } + /** Checks if this matrix is an identity matrix */ + isIdentity() { + return this.a === 1 && this.b === 0 && this.c === 0 && this.d === 1 && this.tx === 0 && this.ty === 0; + } + /** + * Resets this Matrix to an identity (default) matrix. + * @returns This matrix. Good for chaining method calls. + */ + identity() { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.tx = 0; + this.ty = 0; + return this; + } + /** + * Creates a new Matrix object with the same values as this one. + * @returns A copy of this matrix. Good for chaining method calls. + */ + clone() { + const matrix = new Matrix(); + matrix.a = this.a; + matrix.b = this.b; + matrix.c = this.c; + matrix.d = this.d; + matrix.tx = this.tx; + matrix.ty = this.ty; + return matrix; + } + /** + * Changes the values of the given matrix to be the same as the ones in this matrix + * @param matrix - The matrix to copy to. + * @returns The matrix given in parameter with its values updated. + */ + copyTo(matrix) { + matrix.a = this.a; + matrix.b = this.b; + matrix.c = this.c; + matrix.d = this.d; + matrix.tx = this.tx; + matrix.ty = this.ty; + return matrix; + } + /** + * Changes the values of the matrix to be the same as the ones in given matrix + * @param matrix - The matrix to copy from. + * @returns this + */ + copyFrom(matrix) { + this.a = matrix.a; + this.b = matrix.b; + this.c = matrix.c; + this.d = matrix.d; + this.tx = matrix.tx; + this.ty = matrix.ty; + return this; + } + /** + * check to see if two matrices are the same + * @param matrix - The matrix to compare to. + */ + equals(matrix) { + return matrix.a === this.a && matrix.b === this.b && matrix.c === this.c && matrix.d === this.d && matrix.tx === this.tx && matrix.ty === this.ty; + } + toString() { + return `[pixi.js:Matrix a=${this.a} b=${this.b} c=${this.c} d=${this.d} tx=${this.tx} ty=${this.ty}]`; + } + /** + * A default (identity) matrix. + * + * This is a shared object, if you want to modify it consider creating a new `Matrix` + * @readonly + */ + static get IDENTITY() { + return identityMatrix.identity(); + } + /** + * A static Matrix that can be used to avoid creating new objects. + * Will always ensure the matrix is reset to identity when requested. + * Use this object for fast but temporary calculations, as it may be mutated later on. + * This is a different object to the `IDENTITY` object and so can be modified without changing `IDENTITY`. + * @readonly + */ + static get shared() { + return tempMatrix$4.identity(); + } + } + const tempMatrix$4 = new Matrix(); + const identityMatrix = new Matrix(); + + "use strict"; + class ObservablePoint { + /** + * Creates a new `ObservablePoint` + * @param observer - Observer to pass to listen for change events. + * @param {number} [x=0] - position of the point on the x axis + * @param {number} [y=0] - position of the point on the y axis + */ + constructor(observer, x, y) { + this._x = x || 0; + this._y = y || 0; + this._observer = observer; + } + /** + * Creates a clone of this point. + * @param observer - Optional observer to pass to the new observable point. + * @returns a copy of this observable point + */ + clone(observer) { + return new ObservablePoint(observer != null ? observer : this._observer, this._x, this._y); + } + /** + * Sets the point to a new `x` and `y` position. + * If `y` is omitted, both `x` and `y` will be set to `x`. + * @param {number} [x=0] - position of the point on the x axis + * @param {number} [y=x] - position of the point on the y axis + * @returns The observable point instance itself + */ + set(x = 0, y = x) { + if (this._x !== x || this._y !== y) { + this._x = x; + this._y = y; + this._observer._onUpdate(this); + } + return this; + } + /** + * Copies x and y from the given point (`p`) + * @param p - The point to copy from. Can be any of type that is or extends `PointData` + * @returns The observable point instance itself + */ + copyFrom(p) { + if (this._x !== p.x || this._y !== p.y) { + this._x = p.x; + this._y = p.y; + this._observer._onUpdate(this); + } + return this; + } + /** + * Copies this point's x and y into that of the given point (`p`) + * @param p - The point to copy to. Can be any of type that is or extends `PointData` + * @returns The point (`p`) with values updated + */ + copyTo(p) { + p.set(this._x, this._y); + return p; + } + /** + * Accepts another point (`p`) and returns `true` if the given point is equal to this point + * @param p - The point to check + * @returns Returns `true` if both `x` and `y` are equal + */ + equals(p) { + return p.x === this._x && p.y === this._y; + } + toString() { + return `[pixi.js/math:ObservablePoint x=${0} y=${0} scope=${this._observer}]`; + } + /** Position of the observable point on the x axis. */ + get x() { + return this._x; + } + set x(value) { + if (this._x !== value) { + this._x = value; + this._observer._onUpdate(this); + } + } + /** Position of the observable point on the y axis. */ + get y() { + return this._y; + } + set y(value) { + if (this._y !== value) { + this._y = value; + this._observer._onUpdate(this); + } + } + } + + "use strict"; + const uidCache = { + default: -1 + }; + function uid(name = "default") { + if (uidCache[name] === void 0) { + uidCache[name] = -1; + } + return ++uidCache[name]; + } + function resetUids() { + for (const key in uidCache) { + delete uidCache[key]; + } + } + + "use strict"; + const warnings = {}; + const v8_0_0 = "8.0.0"; + function deprecation(version, message, ignoreDepth = 3) { + if (warnings[message]) { + return; + } + let stack = new Error().stack; + if (typeof stack === "undefined") { + console.warn("PixiJS Deprecation Warning: ", `${message} +Deprecated since v${version}`); + } else { + stack = stack.split("\n").splice(ignoreDepth).join("\n"); + if (console.groupCollapsed) { + console.groupCollapsed( + "%cPixiJS Deprecation Warning: %c%s", + "color:#614108;background:#fffbe6", + "font-weight:normal;color:#614108;background:#fffbe6", + `${message} +Deprecated since v${version}` + ); + console.warn(stack); + console.groupEnd(); + } else { + console.warn("PixiJS Deprecation Warning: ", `${message} +Deprecated since v${version}`); + console.warn(stack); + } + } + warnings[message] = true; + } + + "use strict"; + function removeItems(arr, startIdx, removeCount) { + const length = arr.length; + let i; + if (startIdx >= length || removeCount === 0) { + return; + } + removeCount = startIdx + removeCount > length ? length - startIdx : removeCount; + const len = length - removeCount; + for (i = startIdx; i < len; ++i) { + arr[i] = arr[i + removeCount]; + } + arr.length = len; + } + + "use strict"; + const childrenHelperMixin = { + allowChildren: true, + /** + * Removes all children from this container that are within the begin and end indexes. + * @param beginIndex - The beginning position. + * @param endIndex - The ending position. Default value is size of the container. + * @returns - List of removed children + * @memberof scene.Container# + */ + removeChildren(beginIndex = 0, endIndex) { + const end = endIndex != null ? endIndex : this.children.length; + const range = end - beginIndex; + const removed = []; + if (range > 0 && range <= end) { + for (let i = end - 1; i >= beginIndex; i--) { + const child = this.children[i]; + if (!child) + continue; + removed.push(child); + child.parent = null; + } + removeItems(this.children, beginIndex, end); + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.removeChildren(removed); + } + for (let i = 0; i < removed.length; ++i) { + this.emit("childRemoved", removed[i], this, i); + removed[i].emit("removed", this); + } + return removed; + } else if (range === 0 && this.children.length === 0) { + return removed; + } + throw new RangeError("removeChildren: numeric values are outside the acceptable range."); + }, + /** + * Removes a child from the specified index position. + * @param index - The index to get the child from + * @returns The child that was removed. + * @memberof scene.Container# + */ + removeChildAt(index) { + const child = this.getChildAt(index); + return this.removeChild(child); + }, + /** + * Returns the child at the specified index + * @param index - The index to get the child at + * @returns - The child at the given index, if any. + * @memberof scene.Container# + */ + getChildAt(index) { + if (index < 0 || index >= this.children.length) { + throw new Error(`getChildAt: Index (${index}) does not exist.`); + } + return this.children[index]; + }, + /** + * Changes the position of an existing child in the container container + * @param child - The child Container instance for which you want to change the index number + * @param index - The resulting index number for the child container + * @memberof scene.Container# + */ + setChildIndex(child, index) { + if (index < 0 || index >= this.children.length) { + throw new Error(`The index ${index} supplied is out of bounds ${this.children.length}`); + } + this.getChildIndex(child); + this.addChildAt(child, index); + }, + /** + * Returns the index position of a child Container instance + * @param child - The Container instance to identify + * @returns - The index position of the child container to identify + * @memberof scene.Container# + */ + getChildIndex(child) { + const index = this.children.indexOf(child); + if (index === -1) { + throw new Error("The supplied Container must be a child of the caller"); + } + return index; + }, + /** + * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown. + * If the child is already in this container, it will be moved to the specified index. + * @param {Container} child - The child to add. + * @param {number} index - The absolute index where the child will be positioned at the end of the operation. + * @returns {Container} The child that was added. + * @memberof scene.Container# + */ + addChildAt(child, index) { + if (!this.allowChildren) { + deprecation(v8_0_0, "addChildAt: Only Containers will be allowed to add children in v8.0.0"); + } + const { children } = this; + if (index < 0 || index > children.length) { + throw new Error(`${child}addChildAt: The index ${index} supplied is out of bounds ${children.length}`); + } + if (child.parent) { + const currentIndex = child.parent.children.indexOf(child); + if (child.parent === this && currentIndex === index) { + return child; + } + if (currentIndex !== -1) { + child.parent.children.splice(currentIndex, 1); + } + } + if (index === children.length) { + children.push(child); + } else { + children.splice(index, 0, child); + } + child.parent = this; + child.didChange = true; + child.didViewUpdate = false; + child._updateFlags = 15; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.addChild(child); + } + if (this.sortableChildren) + this.sortDirty = true; + this.emit("childAdded", child, this, index); + child.emit("added", this); + return child; + }, + /** + * Swaps the position of 2 Containers within this container. + * @param child - First container to swap + * @param child2 - Second container to swap + */ + swapChildren(child, child2) { + if (child === child2) { + return; + } + const index1 = this.getChildIndex(child); + const index2 = this.getChildIndex(child2); + this.children[index1] = child2; + this.children[index2] = child; + }, + /** + * Remove the Container from its parent Container. If the Container has no parent, do nothing. + * @memberof scene.Container# + */ + removeFromParent() { + var _a; + (_a = this.parent) == null ? void 0 : _a.removeChild(this); + } + }; + + "use strict"; + class FilterEffect { + constructor() { + /** the pipe that knows how to handle this effect */ + this.pipe = "filter"; + /** the priority of this effect */ + this.priority = 1; + } + destroy() { + for (let i = 0; i < this.filters.length; i++) { + this.filters[i].destroy(); + } + this.filters = null; + this.filterArea = null; + } + } + + "use strict"; + class Pool { + /** + * Constructs a new Pool. + * @param ClassType - The constructor of the items in the pool. + * @param {number} [initialSize] - The initial size of the pool. + */ + constructor(ClassType, initialSize) { + this._pool = []; + this._count = 0; + this._index = 0; + this._classType = ClassType; + if (initialSize) { + this.prepopulate(initialSize); + } + } + /** + * Prepopulates the pool with a given number of items. + * @param total - The number of items to add to the pool. + */ + prepopulate(total) { + for (let i = 0; i < total; i++) { + this._pool[this._index++] = new this._classType(); + } + this._count += total; + } + /** + * Gets an item from the pool. Calls the item's `init` method if it exists. + * If there are no items left in the pool, a new one will be created. + * @param {unknown} [data] - Optional data to pass to the item's constructor. + * @returns {T} The item from the pool. + */ + get(data) { + var _a; + let item; + if (this._index > 0) { + item = this._pool[--this._index]; + } else { + item = new this._classType(); + } + (_a = item.init) == null ? void 0 : _a.call(item, data); + return item; + } + /** + * Returns an item to the pool. Calls the item's `reset` method if it exists. + * @param {T} item - The item to return to the pool. + */ + return(item) { + var _a; + (_a = item.reset) == null ? void 0 : _a.call(item); + this._pool[this._index++] = item; + } + /** + * Gets the number of items in the pool. + * @readonly + * @member {number} + */ + get totalSize() { + return this._count; + } + /** + * Gets the number of items in the pool that are free to use without needing to create more. + * @readonly + * @member {number} + */ + get totalFree() { + return this._index; + } + /** + * Gets the number of items in the pool that are currently in use. + * @readonly + * @member {number} + */ + get totalUsed() { + return this._count - this._index; + } + } + + "use strict"; + class PoolGroupClass { + constructor() { + /** + * A map to store the pools by their class type. + * @private + */ + this._poolsByClass = /* @__PURE__ */ new Map(); + } + /** + * Prepopulates a specific pool with a given number of items. + * @template T The type of items in the pool. Must extend PoolItem. + * @param {PoolItemConstructor} Class - The constructor of the items in the pool. + * @param {number} total - The number of items to add to the pool. + */ + prepopulate(Class, total) { + const classPool = this.getPool(Class); + classPool.prepopulate(total); + } + /** + * Gets an item from a specific pool. + * @template T The type of items in the pool. Must extend PoolItem. + * @param {PoolItemConstructor} Class - The constructor of the items in the pool. + * @param {unknown} [data] - Optional data to pass to the item's constructor. + * @returns {T} The item from the pool. + */ + get(Class, data) { + const pool = this.getPool(Class); + return pool.get(data); + } + /** + * Returns an item to its respective pool. + * @param {PoolItem} item - The item to return to the pool. + */ + return(item) { + const pool = this.getPool(item.constructor); + pool.return(item); + } + /** + * Gets a specific pool based on the class type. + * @template T The type of items in the pool. Must extend PoolItem. + * @param {PoolItemConstructor} ClassType - The constructor of the items in the pool. + * @returns {Pool} The pool of the given class type. + */ + getPool(ClassType) { + if (!this._poolsByClass.has(ClassType)) { + this._poolsByClass.set(ClassType, new Pool(ClassType)); + } + return this._poolsByClass.get(ClassType); + } + /** gets the usage stats of each pool in the system */ + stats() { + const stats = {}; + this._poolsByClass.forEach((pool) => { + const name = stats[pool._classType.name] ? pool._classType.name + pool._classType.ID : pool._classType.name; + stats[name] = { + free: pool.totalFree, + used: pool.totalUsed, + size: pool.totalSize + }; + }); + return stats; + } + } + const BigPool = new PoolGroupClass(); + + "use strict"; + class MaskEffectManagerClass { + constructor() { + /** + * @private + */ + this._effectClasses = []; + this._tests = []; + this._initialized = false; + } + init() { + if (this._initialized) + return; + this._initialized = true; + this._effectClasses.forEach((test) => { + this.add({ + test: test.test, + maskClass: test + }); + }); + } + add(test) { + this._tests.push(test); + } + getMaskEffect(item) { + if (!this._initialized) + this.init(); + for (let i = 0; i < this._tests.length; i++) { + const test = this._tests[i]; + if (test.test(item)) { + return BigPool.get(test.maskClass, item); + } + } + return item; + } + returnMaskEffect(effect) { + BigPool.return(effect); + } + } + const MaskEffectManager = new MaskEffectManagerClass(); + extensions.handleByList(ExtensionType.MaskEffect, MaskEffectManager._effectClasses); + + "use strict"; + const effectsMixin = { + _maskEffect: null, + _filterEffect: null, + /** + * @todo Needs docs. + * @memberof scene.Container# + * @type {Array} + */ + effects: [], + /** + * @todo Needs docs. + * @param effect - The effect to add. + * @memberof scene.Container# + * @ignore + */ + addEffect(effect) { + const index = this.effects.indexOf(effect); + if (index !== -1) + return; + this.effects.push(effect); + this.effects.sort((a, b) => a.priority - b.priority); + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.structureDidChange = true; + } + this._updateIsSimple(); + }, + /** + * @todo Needs docs. + * @param effect - The effect to remove. + * @memberof scene.Container# + * @ignore + */ + removeEffect(effect) { + const index = this.effects.indexOf(effect); + if (index === -1) + return; + this.effects.splice(index, 1); + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + this._updateIsSimple(); + }, + set mask(value) { + const effect = this._maskEffect; + if ((effect == null ? void 0 : effect.mask) === value) + return; + if (effect) { + this.removeEffect(effect); + MaskEffectManager.returnMaskEffect(effect); + this._maskEffect = null; + } + if (value === null || value === void 0) + return; + this._maskEffect = MaskEffectManager.getMaskEffect(value); + this.addEffect(this._maskEffect); + }, + /** + * Sets a mask for the displayObject. A mask is an object that limits the visibility of an + * object to the shape of the mask applied to it. In PixiJS a regular mask must be a + * {@link Graphics} or a {@link Sprite} object. This allows for much faster masking in canvas as it + * utilities shape clipping. Furthermore, a mask of an object must be in the subtree of its parent. + * Otherwise, `getLocalBounds` may calculate incorrect bounds, which makes the container's width and height wrong. + * To remove a mask, set this property to `null`. + * + * For sprite mask both alpha and red channel are used. Black mask is the same as transparent mask. + * @example + * import { Graphics, Sprite } from 'pixi.js'; + * + * const graphics = new Graphics(); + * graphics.beginFill(0xFF3300); + * graphics.drawRect(50, 250, 100, 100); + * graphics.endFill(); + * + * const sprite = new Sprite(texture); + * sprite.mask = graphics; + * @memberof scene.Container# + */ + get mask() { + var _a; + return (_a = this._maskEffect) == null ? void 0 : _a.mask; + }, + set filters(value) { + var _a; + if (!Array.isArray(value) && value) + value = [value]; + const effect = this._filterEffect || (this._filterEffect = new FilterEffect()); + value = value; + const hasFilters = (value == null ? void 0 : value.length) > 0; + const hadFilters = ((_a = effect.filters) == null ? void 0 : _a.length) > 0; + const didChange = hasFilters !== hadFilters; + value = Array.isArray(value) ? value.slice(0) : value; + effect.filters = Object.freeze(value); + if (didChange) { + if (hasFilters) { + this.addEffect(effect); + } else { + this.removeEffect(effect); + effect.filters = value != null ? value : null; + } + } + }, + /** + * Sets the filters for the displayObject. + * IMPORTANT: This is a WebGL only feature and will be ignored by the canvas renderer. + * To remove filters simply set this property to `'null'`. + * @memberof scene.Container# + */ + get filters() { + var _a; + return (_a = this._filterEffect) == null ? void 0 : _a.filters; + }, + set filterArea(value) { + this._filterEffect || (this._filterEffect = new FilterEffect()); + this._filterEffect.filterArea = value; + }, + /** + * The area the filter is applied to. This is used as more of an optimization + * rather than figuring out the dimensions of the displayObject each frame you can set this rectangle. + * + * Also works as an interaction mask. + * @memberof scene.Container# + */ + get filterArea() { + var _a; + return (_a = this._filterEffect) == null ? void 0 : _a.filterArea; + } + }; + + "use strict"; + const findMixin = { + /** + * The instance label of the object. + * @memberof scene.Container# + * @member {string} label + */ + label: null, + /** + * The instance name of the object. + * @deprecated since 8.0.0 + * @see scene.Container#label + * @member {string} name + * @memberof scene.Container# + */ + get name() { + deprecation(v8_0_0, "Container.name property has been removed, use Container.label instead"); + return this.label; + }, + set name(value) { + deprecation(v8_0_0, "Container.name property has been removed, use Container.label instead"); + this.label = value; + }, + /** + * @method getChildByName + * @deprecated since 8.0.0 + * @param {string} name - Instance name. + * @param {boolean}[deep=false] - Whether to search recursively + * @returns {Container} The child with the specified name. + * @see scene.Container#getChildByLabel + * @memberof scene.Container# + */ + getChildByName(name, deep = false) { + return this.getChildByLabel(name, deep); + }, + /** + * Returns the first child in the container with the specified label. + * + * Recursive searches are done in a pre-order traversal. + * @memberof scene.Container# + * @param {string|RegExp} label - Instance label. + * @param {boolean}[deep=false] - Whether to search recursively + * @returns {Container} The child with the specified label. + */ + getChildByLabel(label, deep = false) { + const children = this.children; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + if (child.label === label || label instanceof RegExp && label.test(child.label)) + return child; + } + if (deep) { + for (let i = 0; i < children.length; i++) { + const child = children[i]; + const found = child.getChildByLabel(label, true); + if (found) { + return found; + } + } + } + return null; + }, + /** + * Returns all children in the container with the specified label. + * @memberof scene.Container# + * @param {string|RegExp} label - Instance label. + * @param {boolean}[deep=false] - Whether to search recursively + * @param {Container[]} [out=[]] - The array to store matching children in. + * @returns {Container[]} An array of children with the specified label. + */ + getChildrenByLabel(label, deep = false, out = []) { + const children = this.children; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + if (child.label === label || label instanceof RegExp && label.test(child.label)) { + out.push(child); + } + } + if (deep) { + for (let i = 0; i < children.length; i++) { + children[i].getChildrenByLabel(label, true, out); + } + } + return out; + } + }; + + "use strict"; + const tempPoints = [new Point(), new Point(), new Point(), new Point()]; + class Rectangle { + /** + * @param x - The X coordinate of the upper-left corner of the rectangle + * @param y - The Y coordinate of the upper-left corner of the rectangle + * @param width - The overall width of the rectangle + * @param height - The overall height of the rectangle + */ + constructor(x = 0, y = 0, width = 0, height = 0) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'rectangle' + */ + this.type = "rectangle"; + this.x = Number(x); + this.y = Number(y); + this.width = Number(width); + this.height = Number(height); + } + /** Returns the left edge of the rectangle. */ + get left() { + return this.x; + } + /** Returns the right edge of the rectangle. */ + get right() { + return this.x + this.width; + } + /** Returns the top edge of the rectangle. */ + get top() { + return this.y; + } + /** Returns the bottom edge of the rectangle. */ + get bottom() { + return this.y + this.height; + } + /** Determines whether the Rectangle is empty. */ + isEmpty() { + return this.left === this.right || this.top === this.bottom; + } + /** A constant empty rectangle. This is a new object every time the property is accessed */ + static get EMPTY() { + return new Rectangle(0, 0, 0, 0); + } + /** + * Creates a clone of this Rectangle + * @returns a copy of the rectangle + */ + clone() { + return new Rectangle(this.x, this.y, this.width, this.height); + } + /** + * Converts a Bounds object to a Rectangle object. + * @param bounds - The bounds to copy and convert to a rectangle. + * @returns Returns itself. + */ + copyFromBounds(bounds) { + this.x = bounds.minX; + this.y = bounds.minY; + this.width = bounds.maxX - bounds.minX; + this.height = bounds.maxY - bounds.minY; + return this; + } + /** + * Copies another rectangle to this one. + * @param rectangle - The rectangle to copy from. + * @returns Returns itself. + */ + copyFrom(rectangle) { + this.x = rectangle.x; + this.y = rectangle.y; + this.width = rectangle.width; + this.height = rectangle.height; + return this; + } + /** + * Copies this rectangle to another one. + * @param rectangle - The rectangle to copy to. + * @returns Returns given parameter. + */ + copyTo(rectangle) { + rectangle.copyFrom(this); + return rectangle; + } + /** + * Checks whether the x and y coordinates given are contained within this Rectangle + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @returns Whether the x/y coordinates are within this Rectangle + */ + contains(x, y) { + if (this.width <= 0 || this.height <= 0) { + return false; + } + if (x >= this.x && x < this.x + this.width) { + if (y >= this.y && y < this.y + this.height) { + return true; + } + } + return false; + } + /** + * Checks whether the x and y coordinates given are contained within this rectangle including the stroke. + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @param strokeWidth - The width of the line to check + * @returns Whether the x/y coordinates are within this rectangle + */ + strokeContains(x, y, strokeWidth) { + const { width, height } = this; + if (width <= 0 || height <= 0) + return false; + const _x = this.x; + const _y = this.y; + const outerLeft = _x - strokeWidth / 2; + const outerRight = _x + width + strokeWidth / 2; + const outerTop = _y - strokeWidth / 2; + const outerBottom = _y + height + strokeWidth / 2; + const innerLeft = _x + strokeWidth / 2; + const innerRight = _x + width - strokeWidth / 2; + const innerTop = _y + strokeWidth / 2; + const innerBottom = _y + height - strokeWidth / 2; + return x >= outerLeft && x <= outerRight && y >= outerTop && y <= outerBottom && !(x > innerLeft && x < innerRight && y > innerTop && y < innerBottom); + } + /** + * Determines whether the `other` Rectangle transformed by `transform` intersects with `this` Rectangle object. + * Returns true only if the area of the intersection is >0, this means that Rectangles + * sharing a side are not overlapping. Another side effect is that an arealess rectangle + * (width or height equal to zero) can't intersect any other rectangle. + * @param {Rectangle} other - The Rectangle to intersect with `this`. + * @param {Matrix} transform - The transformation matrix of `other`. + * @returns {boolean} A value of `true` if the transformed `other` Rectangle intersects with `this`; otherwise `false`. + */ + intersects(other, transform) { + if (!transform) { + const x02 = this.x < other.x ? other.x : this.x; + const x12 = this.right > other.right ? other.right : this.right; + if (x12 <= x02) { + return false; + } + const y02 = this.y < other.y ? other.y : this.y; + const y12 = this.bottom > other.bottom ? other.bottom : this.bottom; + return y12 > y02; + } + const x0 = this.left; + const x1 = this.right; + const y0 = this.top; + const y1 = this.bottom; + if (x1 <= x0 || y1 <= y0) { + return false; + } + const lt = tempPoints[0].set(other.left, other.top); + const lb = tempPoints[1].set(other.left, other.bottom); + const rt = tempPoints[2].set(other.right, other.top); + const rb = tempPoints[3].set(other.right, other.bottom); + if (rt.x <= lt.x || lb.y <= lt.y) { + return false; + } + const s = Math.sign(transform.a * transform.d - transform.b * transform.c); + if (s === 0) { + return false; + } + transform.apply(lt, lt); + transform.apply(lb, lb); + transform.apply(rt, rt); + transform.apply(rb, rb); + if (Math.max(lt.x, lb.x, rt.x, rb.x) <= x0 || Math.min(lt.x, lb.x, rt.x, rb.x) >= x1 || Math.max(lt.y, lb.y, rt.y, rb.y) <= y0 || Math.min(lt.y, lb.y, rt.y, rb.y) >= y1) { + return false; + } + const nx = s * (lb.y - lt.y); + const ny = s * (lt.x - lb.x); + const n00 = nx * x0 + ny * y0; + const n10 = nx * x1 + ny * y0; + const n01 = nx * x0 + ny * y1; + const n11 = nx * x1 + ny * y1; + if (Math.max(n00, n10, n01, n11) <= nx * lt.x + ny * lt.y || Math.min(n00, n10, n01, n11) >= nx * rb.x + ny * rb.y) { + return false; + } + const mx = s * (lt.y - rt.y); + const my = s * (rt.x - lt.x); + const m00 = mx * x0 + my * y0; + const m10 = mx * x1 + my * y0; + const m01 = mx * x0 + my * y1; + const m11 = mx * x1 + my * y1; + if (Math.max(m00, m10, m01, m11) <= mx * lt.x + my * lt.y || Math.min(m00, m10, m01, m11) >= mx * rb.x + my * rb.y) { + return false; + } + return true; + } + /** + * Pads the rectangle making it grow in all directions. + * If paddingY is omitted, both paddingX and paddingY will be set to paddingX. + * @param paddingX - The horizontal padding amount. + * @param paddingY - The vertical padding amount. + * @returns Returns itself. + */ + pad(paddingX = 0, paddingY = paddingX) { + this.x -= paddingX; + this.y -= paddingY; + this.width += paddingX * 2; + this.height += paddingY * 2; + return this; + } + /** + * Fits this rectangle around the passed one. + * @param rectangle - The rectangle to fit. + * @returns Returns itself. + */ + fit(rectangle) { + const x1 = Math.max(this.x, rectangle.x); + const x2 = Math.min(this.x + this.width, rectangle.x + rectangle.width); + const y1 = Math.max(this.y, rectangle.y); + const y2 = Math.min(this.y + this.height, rectangle.y + rectangle.height); + this.x = x1; + this.width = Math.max(x2 - x1, 0); + this.y = y1; + this.height = Math.max(y2 - y1, 0); + return this; + } + /** + * Enlarges rectangle that way its corners lie on grid + * @param resolution - resolution + * @param eps - precision + * @returns Returns itself. + */ + ceil(resolution = 1, eps = 1e-3) { + const x2 = Math.ceil((this.x + this.width - eps) * resolution) / resolution; + const y2 = Math.ceil((this.y + this.height - eps) * resolution) / resolution; + this.x = Math.floor((this.x + eps) * resolution) / resolution; + this.y = Math.floor((this.y + eps) * resolution) / resolution; + this.width = x2 - this.x; + this.height = y2 - this.y; + return this; + } + /** + * Enlarges this rectangle to include the passed rectangle. + * @param rectangle - The rectangle to include. + * @returns Returns itself. + */ + enlarge(rectangle) { + const x1 = Math.min(this.x, rectangle.x); + const x2 = Math.max(this.x + this.width, rectangle.x + rectangle.width); + const y1 = Math.min(this.y, rectangle.y); + const y2 = Math.max(this.y + this.height, rectangle.y + rectangle.height); + this.x = x1; + this.width = x2 - x1; + this.y = y1; + this.height = y2 - y1; + return this; + } + /** + * Returns the framing rectangle of the rectangle as a Rectangle object + * @param out - optional rectangle to store the result + * @returns The framing rectangle + */ + getBounds(out) { + out = out || new Rectangle(); + out.copyFrom(this); + return out; + } + toString() { + return `[pixi.js/math:Rectangle x=${this.x} y=${this.y} width=${this.width} height=${this.height}]`; + } + } + + "use strict"; + const defaultMatrix = new Matrix(); + class Bounds { + constructor(minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity) { + /** @default Infinity */ + this.minX = Infinity; + /** @default Infinity */ + this.minY = Infinity; + /** @default -Infinity */ + this.maxX = -Infinity; + /** @default -Infinity */ + this.maxY = -Infinity; + this.matrix = defaultMatrix; + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** + * Checks if bounds are empty. + * @returns - True if empty. + */ + isEmpty() { + return this.minX > this.maxX || this.minY > this.maxY; + } + /** The bounding rectangle of the bounds. */ + get rectangle() { + if (!this._rectangle) { + this._rectangle = new Rectangle(); + } + const rectangle = this._rectangle; + if (this.minX > this.maxX || this.minY > this.maxY) { + rectangle.x = 0; + rectangle.y = 0; + rectangle.width = 0; + rectangle.height = 0; + } else { + rectangle.copyFromBounds(this); + } + return rectangle; + } + /** Clears the bounds and resets. */ + clear() { + this.minX = Infinity; + this.minY = Infinity; + this.maxX = -Infinity; + this.maxY = -Infinity; + this.matrix = defaultMatrix; + return this; + } + /** + * Sets the bounds. + * @param x0 - left X of frame + * @param y0 - top Y of frame + * @param x1 - right X of frame + * @param y1 - bottom Y of frame + */ + set(x0, y0, x1, y1) { + this.minX = x0; + this.minY = y0; + this.maxX = x1; + this.maxY = y1; + } + /** + * Adds sprite frame + * @param x0 - left X of frame + * @param y0 - top Y of frame + * @param x1 - right X of frame + * @param y1 - bottom Y of frame + * @param matrix + */ + addFrame(x0, y0, x1, y1, matrix) { + matrix || (matrix = this.matrix); + const a = matrix.a; + const b = matrix.b; + const c = matrix.c; + const d = matrix.d; + const tx = matrix.tx; + const ty = matrix.ty; + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + let x = a * x0 + c * y0 + tx; + let y = b * x0 + d * y0 + ty; + if (x < minX) + minX = x; + if (y < minY) + minY = y; + if (x > maxX) + maxX = x; + if (y > maxY) + maxY = y; + x = a * x1 + c * y0 + tx; + y = b * x1 + d * y0 + ty; + if (x < minX) + minX = x; + if (y < minY) + minY = y; + if (x > maxX) + maxX = x; + if (y > maxY) + maxY = y; + x = a * x0 + c * y1 + tx; + y = b * x0 + d * y1 + ty; + if (x < minX) + minX = x; + if (y < minY) + minY = y; + if (x > maxX) + maxX = x; + if (y > maxY) + maxY = y; + x = a * x1 + c * y1 + tx; + y = b * x1 + d * y1 + ty; + if (x < minX) + minX = x; + if (y < minY) + minY = y; + if (x > maxX) + maxX = x; + if (y > maxY) + maxY = y; + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** + * Adds a rectangle to the bounds. + * @param rect - The rectangle to be added. + * @param matrix - The matrix to apply to the bounds. + */ + addRect(rect, matrix) { + this.addFrame(rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, matrix); + } + /** + * Adds other {@link Bounds}. + * @param bounds - The Bounds to be added + * @param matrix + */ + addBounds(bounds, matrix) { + this.addFrame(bounds.minX, bounds.minY, bounds.maxX, bounds.maxY, matrix); + } + /** + * Adds other Bounds, masked with Bounds. + * @param mask - The Bounds to be added. + */ + addBoundsMask(mask) { + this.minX = this.minX > mask.minX ? this.minX : mask.minX; + this.minY = this.minY > mask.minY ? this.minY : mask.minY; + this.maxX = this.maxX < mask.maxX ? this.maxX : mask.maxX; + this.maxY = this.maxY < mask.maxY ? this.maxY : mask.maxY; + } + /** + * Adds other Bounds, multiplied with matrix. + * @param matrix - The matrix to apply to the bounds. + */ + applyMatrix(matrix) { + const minX = this.minX; + const minY = this.minY; + const maxX = this.maxX; + const maxY = this.maxY; + const { a, b, c, d, tx, ty } = matrix; + let x = a * minX + c * minY + tx; + let y = b * minX + d * minY + ty; + this.minX = x; + this.minY = y; + this.maxX = x; + this.maxY = y; + x = a * maxX + c * minY + tx; + y = b * maxX + d * minY + ty; + this.minX = x < this.minX ? x : this.minX; + this.minY = y < this.minY ? y : this.minY; + this.maxX = x > this.maxX ? x : this.maxX; + this.maxY = y > this.maxY ? y : this.maxY; + x = a * minX + c * maxY + tx; + y = b * minX + d * maxY + ty; + this.minX = x < this.minX ? x : this.minX; + this.minY = y < this.minY ? y : this.minY; + this.maxX = x > this.maxX ? x : this.maxX; + this.maxY = y > this.maxY ? y : this.maxY; + x = a * maxX + c * maxY + tx; + y = b * maxX + d * maxY + ty; + this.minX = x < this.minX ? x : this.minX; + this.minY = y < this.minY ? y : this.minY; + this.maxX = x > this.maxX ? x : this.maxX; + this.maxY = y > this.maxY ? y : this.maxY; + } + /** + * Resizes the bounds object to include the given rectangle. + * @param rect - The rectangle to be included. + */ + fit(rect) { + if (this.minX < rect.left) + this.minX = rect.left; + if (this.maxX > rect.right) + this.maxX = rect.right; + if (this.minY < rect.top) + this.minY = rect.top; + if (this.maxY > rect.bottom) + this.maxY = rect.bottom; + return this; + } + /** + * Resizes the bounds object to include the given bounds. + * @param left - The left value of the bounds. + * @param right - The right value of the bounds. + * @param top - The top value of the bounds. + * @param bottom - The bottom value of the bounds. + */ + fitBounds(left, right, top, bottom) { + if (this.minX < left) + this.minX = left; + if (this.maxX > right) + this.maxX = right; + if (this.minY < top) + this.minY = top; + if (this.maxY > bottom) + this.maxY = bottom; + return this; + } + /** + * Pads bounds object, making it grow in all directions. + * If paddingY is omitted, both paddingX and paddingY will be set to paddingX. + * @param paddingX - The horizontal padding amount. + * @param paddingY - The vertical padding amount. + */ + pad(paddingX, paddingY = paddingX) { + this.minX -= paddingX; + this.maxX += paddingX; + this.minY -= paddingY; + this.maxY += paddingY; + return this; + } + /** Ceils the bounds. */ + ceil() { + this.minX = Math.floor(this.minX); + this.minY = Math.floor(this.minY); + this.maxX = Math.ceil(this.maxX); + this.maxY = Math.ceil(this.maxY); + return this; + } + /** Clones the bounds. */ + clone() { + return new Bounds(this.minX, this.minY, this.maxX, this.maxY); + } + /** + * Scales the bounds by the given values + * @param x - The X value to scale by. + * @param y - The Y value to scale by. + */ + scale(x, y = x) { + this.minX *= x; + this.minY *= y; + this.maxX *= x; + this.maxY *= y; + return this; + } + /** the x value of the bounds. */ + get x() { + return this.minX; + } + set x(value) { + const width = this.maxX - this.minX; + this.minX = value; + this.maxX = value + width; + } + /** the y value of the bounds. */ + get y() { + return this.minY; + } + set y(value) { + const height = this.maxY - this.minY; + this.minY = value; + this.maxY = value + height; + } + /** the width value of the bounds. */ + get width() { + return this.maxX - this.minX; + } + set width(value) { + this.maxX = this.minX + value; + } + /** the height value of the bounds. */ + get height() { + return this.maxY - this.minY; + } + set height(value) { + this.maxY = this.minY + value; + } + /** the left value of the bounds. */ + get left() { + return this.minX; + } + /** the right value of the bounds. */ + get right() { + return this.maxX; + } + /** the top value of the bounds. */ + get top() { + return this.minY; + } + /** the bottom value of the bounds. */ + get bottom() { + return this.maxY; + } + /** Is the bounds positive. */ + get isPositive() { + return this.maxX - this.minX > 0 && this.maxY - this.minY > 0; + } + get isValid() { + return this.minX + this.minY !== Infinity; + } + /** + * Adds screen vertices from array + * @param vertexData - calculated vertices + * @param beginOffset - begin offset + * @param endOffset - end offset, excluded + * @param matrix + */ + addVertexData(vertexData, beginOffset, endOffset, matrix) { + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + matrix || (matrix = this.matrix); + const a = matrix.a; + const b = matrix.b; + const c = matrix.c; + const d = matrix.d; + const tx = matrix.tx; + const ty = matrix.ty; + for (let i = beginOffset; i < endOffset; i += 2) { + const localX = vertexData[i]; + const localY = vertexData[i + 1]; + const x = a * localX + c * localY + tx; + const y = b * localX + d * localY + ty; + minX = x < minX ? x : minX; + minY = y < minY ? y : minY; + maxX = x > maxX ? x : maxX; + maxY = y > maxY ? y : maxY; + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** + * Checks if the point is contained within the bounds. + * @param x - x coordinate + * @param y - y coordinate + */ + containsPoint(x, y) { + if (this.minX <= x && this.minY <= y && this.maxX >= x && this.maxY >= y) { + return true; + } + return false; + } + toString() { + return `[pixi.js:Bounds minX=${this.minX} minY=${this.minY} maxX=${this.maxX} maxY=${this.maxY} width=${this.width} height=${this.height}]`; + } + } + + "use strict"; + const matrixPool = new Pool(Matrix); + const boundsPool = new Pool(Bounds); + + "use strict"; + function getGlobalBounds(target, skipUpdateTransform, bounds) { + bounds.clear(); + let parentTransform; + let pooledMatrix; + if (target.parent) { + if (!skipUpdateTransform) { + pooledMatrix = matrixPool.get().identity(); + parentTransform = updateTransformBackwards(target, pooledMatrix); + } else { + parentTransform = target.parent.worldTransform; + } + } else { + parentTransform = Matrix.IDENTITY; + } + _getGlobalBounds(target, bounds, parentTransform, skipUpdateTransform); + if (pooledMatrix) { + matrixPool.return(pooledMatrix); + } + if (!bounds.isValid) { + bounds.set(0, 0, 0, 0); + } + return bounds; + } + function _getGlobalBounds(target, bounds, parentTransform, skipUpdateTransform) { + var _a, _b; + if (!target.visible || !target.measurable) + return; + let worldTransform; + if (!skipUpdateTransform) { + target.updateLocalTransform(); + worldTransform = matrixPool.get(); + worldTransform.appendFrom(target.localTransform, parentTransform); + } else { + worldTransform = target.worldTransform; + } + const parentBounds = bounds; + const preserveBounds = !!target.effects.length; + if (preserveBounds) { + bounds = boundsPool.get().clear(); + } + if (target.boundsArea) { + bounds.addRect(target.boundsArea, worldTransform); + } else { + if (target.addBounds) { + bounds.matrix = worldTransform; + target.addBounds(bounds); + } + for (let i = 0; i < target.children.length; i++) { + _getGlobalBounds(target.children[i], bounds, worldTransform, skipUpdateTransform); + } + } + if (preserveBounds) { + for (let i = 0; i < target.effects.length; i++) { + (_b = (_a = target.effects[i]).addBounds) == null ? void 0 : _b.call(_a, bounds); + } + parentBounds.addBounds(bounds, Matrix.IDENTITY); + boundsPool.return(bounds); + } + if (!skipUpdateTransform) { + matrixPool.return(worldTransform); + } + } + function updateTransformBackwards(target, parentTransform) { + const parent = target.parent; + if (parent) { + updateTransformBackwards(parent, parentTransform); + parent.updateLocalTransform(); + parentTransform.append(parent.localTransform); + } + return parentTransform; + } + + "use strict"; + let warnCount = 0; + const maxWarnings = 500; + function warn(...args) { + if (warnCount === maxWarnings) + return; + warnCount++; + if (warnCount === maxWarnings) { + console.warn("PixiJS Warning: too many warnings, no more warnings will be reported to the console by PixiJS."); + } else { + console.warn("PixiJS Warning: ", ...args); + } + } + + "use strict"; + function getLocalBounds(target, bounds, relativeMatrix) { + bounds.clear(); + relativeMatrix || (relativeMatrix = Matrix.IDENTITY); + _getLocalBounds(target, bounds, relativeMatrix, target, true); + if (!bounds.isValid) { + bounds.set(0, 0, 0, 0); + } + return bounds; + } + function _getLocalBounds(target, bounds, parentTransform, rootContainer, isRoot) { + var _a, _b; + let relativeTransform; + if (!isRoot) { + if (!target.visible || !target.measurable) + return; + target.updateLocalTransform(); + const localTransform = target.localTransform; + relativeTransform = matrixPool.get(); + relativeTransform.appendFrom(localTransform, parentTransform); + } else { + relativeTransform = matrixPool.get(); + relativeTransform = parentTransform.copyTo(relativeTransform); + } + const parentBounds = bounds; + const preserveBounds = !!target.effects.length; + if (preserveBounds) { + bounds = boundsPool.get().clear(); + } + if (target.boundsArea) { + bounds.addRect(target.boundsArea, relativeTransform); + } else { + if (target.renderPipeId) { + bounds.matrix = relativeTransform; + target.addBounds(bounds); + } + const children = target.children; + for (let i = 0; i < children.length; i++) { + _getLocalBounds(children[i], bounds, relativeTransform, rootContainer, false); + } + } + if (preserveBounds) { + for (let i = 0; i < target.effects.length; i++) { + (_b = (_a = target.effects[i]).addLocalBounds) == null ? void 0 : _b.call(_a, bounds, rootContainer); + } + parentBounds.addBounds(bounds, Matrix.IDENTITY); + boundsPool.return(bounds); + } + matrixPool.return(relativeTransform); + } + function getParent(target, root, matrix) { + const parent = target.parent; + if (!parent) { + warn("Item is not inside the root container"); + return; + } + if (parent !== root) { + getParent(parent, root, matrix); + parent.updateLocalTransform(); + matrix.append(parent.localTransform); + } + } + + "use strict"; + function checkChildrenDidChange(container, previousData) { + const children = container.children; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + const changeId = (child.uid & 255) << 24 | child._didChangeId & 16777215; + if (previousData.data[previousData.index] !== changeId) { + previousData.data[previousData.index] = changeId; + previousData.didChange = true; + } + previousData.index++; + if (child.children.length) { + checkChildrenDidChange(child, previousData); + } + } + return previousData.didChange; + } + + "use strict"; + const tempMatrix$3 = new Matrix(); + const measureMixin = { + _localBoundsCacheId: -1, + _localBoundsCacheData: null, + _setWidth(value, localWidth) { + const sign = Math.sign(this.scale.x) || 1; + if (localWidth !== 0) { + this.scale.x = value / localWidth * sign; + } else { + this.scale.x = sign; + } + }, + _setHeight(value, localHeight) { + const sign = Math.sign(this.scale.y) || 1; + if (localHeight !== 0) { + this.scale.y = value / localHeight * sign; + } else { + this.scale.y = sign; + } + }, + /** + * Retrieves the local bounds of the container as a Bounds object. + * @returns - The bounding area. + * @memberof scene.Container# + */ + getLocalBounds() { + if (!this._localBoundsCacheData) { + this._localBoundsCacheData = { + data: [], + index: 1, + didChange: false, + localBounds: new Bounds() + }; + } + const localBoundsCacheData = this._localBoundsCacheData; + localBoundsCacheData.index = 1; + localBoundsCacheData.didChange = false; + if (localBoundsCacheData.data[0] !== this._didChangeId >> 12) { + localBoundsCacheData.didChange = true; + localBoundsCacheData.data[0] = this._didChangeId >> 12; + } + checkChildrenDidChange(this, localBoundsCacheData); + if (localBoundsCacheData.didChange) { + getLocalBounds(this, localBoundsCacheData.localBounds, tempMatrix$3); + } + return localBoundsCacheData.localBounds; + }, + /** + * Calculates and returns the (world) bounds of the display object as a [Rectangle]{@link Rectangle}. + * @param skipUpdate - Setting to `true` will stop the transforms of the scene graph from + * being updated. This means the calculation returned MAY be out of date BUT will give you a + * nice performance boost. + * @param bounds - Optional bounds to store the result of the bounds calculation. + * @returns - The minimum axis-aligned rectangle in world space that fits around this object. + * @memberof scene.Container# + */ + getBounds(skipUpdate, bounds) { + return getGlobalBounds(this, skipUpdate, bounds || new Bounds()); + } + }; + + "use strict"; + const onRenderMixin = { + _onRender: null, + set onRender(func) { + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (!func) { + if (this._onRender) { + renderGroup == null ? void 0 : renderGroup.removeOnRender(this); + } + this._onRender = null; + return; + } + if (!this._onRender) { + renderGroup == null ? void 0 : renderGroup.addOnRender(this); + } + this._onRender = func; + }, + /** + * This callback is used when the container is rendered. This is where you should add your custom + * logic that is needed to be run every frame. + * + * In v7 many users used `updateTransform` for this, however the way v8 renders objects is different + * and "updateTransform" is no longer called every frame + * @example + * const container = new Container(); + * container.onRender = () => { + * container.rotation += 0.01; + * }; + * @memberof scene.Container# + */ + get onRender() { + return this._onRender; + } + }; + + "use strict"; + const sortMixin = { + _zIndex: 0, + /** + * Should children be sorted by zIndex at the next render call. + * + * Will get automatically set to true if a new child is added, or if a child's zIndex changes. + * @type {boolean} + * @memberof scene.Container# + */ + sortDirty: false, + /** + * If set to true, the container will sort its children by `zIndex` value + * when the next render is called, or manually if `sortChildren()` is called. + * + * This actually changes the order of elements in the array, so should be treated + * as a basic solution that is not performant compared to other solutions, + * such as {@link https://github.com/pixijs/layers PixiJS Layers} + * + * Also be aware of that this may not work nicely with the `addChildAt()` function, + * as the `zIndex` sorting may cause the child to automatically sorted to another position. + * @type {boolean} + * @memberof scene.Container# + */ + sortableChildren: false, + /** + * The zIndex of the container. + * + * Setting this value, will automatically set the parent to be sortable. Children will be automatically + * sorted by zIndex value; a higher value will mean it will be moved towards the end of the array, + * and thus rendered on top of other display objects within the same container. + * @see scene.Container#sortableChildren + * @memberof scene.Container# + */ + get zIndex() { + return this._zIndex; + }, + set zIndex(value) { + if (this._zIndex === value) + return; + this._zIndex = value; + this.depthOfChildModified(); + }, + depthOfChildModified() { + if (this.parent) { + this.parent.sortableChildren = true; + this.parent.sortDirty = true; + } + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + }, + /** + * Sorts children by zIndex. + * @memberof scene.Container# + */ + sortChildren() { + if (!this.sortDirty) + return; + this.sortDirty = false; + this.children.sort(sortChildren); + } + }; + function sortChildren(a, b) { + return a._zIndex - b._zIndex; + } + + "use strict"; + const toLocalGlobalMixin = { + /** + * Returns the global position of the container. + * @param point - The optional point to write the global value to. + * @param skipUpdate - Should we skip the update transform. + * @returns - The updated point. + * @memberof scene.Container# + */ + getGlobalPosition(point = new Point(), skipUpdate = false) { + if (this.parent) { + this.parent.toGlobal(this._position, point, skipUpdate); + } else { + point.x = this._position.x; + point.y = this._position.y; + } + return point; + }, + /** + * Calculates the global position of the container. + * @param position - The world origin to calculate from. + * @param point - A Point object in which to store the value, optional + * (otherwise will create a new Point). + * @param skipUpdate - Should we skip the update transform. + * @returns - A point object representing the position of this object. + * @memberof scene.Container# + */ + toGlobal(position, point, skipUpdate = false) { + if (!skipUpdate) { + this.updateLocalTransform(); + const globalMatrix = updateTransformBackwards(this, new Matrix()); + globalMatrix.append(this.localTransform); + return globalMatrix.apply(position, point); + } + return this.worldTransform.apply(position, point); + }, + /** + * Calculates the local position of the container relative to another point. + * @param position - The world origin to calculate from. + * @param from - The Container to calculate the global position from. + * @param point - A Point object in which to store the value, optional + * (otherwise will create a new Point). + * @param skipUpdate - Should we skip the update transform + * @returns - A point object representing the position of this object + * @memberof scene.Container# + */ + toLocal(position, from, point, skipUpdate) { + if (from) { + position = from.toGlobal(position, point, skipUpdate); + } + if (!skipUpdate) { + this.updateLocalTransform(); + const globalMatrix = updateTransformBackwards(this, new Matrix()); + globalMatrix.append(this.localTransform); + return globalMatrix.applyInverse(position, point); + } + return this.worldTransform.applyInverse(position, point); + } + }; + + "use strict"; + class InstructionSet { + constructor() { + /** a unique id for this instruction set used through the renderer */ + this.uid = uid("instructionSet"); + /** the array of instructions */ + this.instructions = []; + /** the actual size of the array (any instructions passed this should be ignored) */ + this.instructionSize = 0; + } + /** reset the instruction set so it can be reused set size back to 0 */ + reset() { + this.instructionSize = 0; + } + /** + * Add an instruction to the set + * @param instruction - add an instruction to the set + */ + add(instruction) { + this.instructions[this.instructionSize++] = instruction; + } + /** + * Log the instructions to the console (for debugging) + * @internal + * @ignore + */ + log() { + this.instructions.length = this.instructionSize; + console.table(this.instructions, ["type", "action"]); + } + } + + "use strict"; + class RenderGroup { + constructor(root) { + this.renderPipeId = "renderGroup"; + this.root = null; + this.canBundle = false; + this.renderGroupParent = null; + this.renderGroupChildren = []; + this.worldTransform = new Matrix(); + this.worldColorAlpha = 4294967295; + this.worldColor = 16777215; + this.worldAlpha = 1; + // these updates are transform changes.. + this.childrenToUpdate = /* @__PURE__ */ Object.create(null); + this.updateTick = 0; + // these update are renderable changes.. + this.childrenRenderablesToUpdate = { list: [], index: 0 }; + // other + this.structureDidChange = true; + this.instructionSet = new InstructionSet(); + this._onRenderContainers = []; + this.root = root; + if (root._onRender) + this.addOnRender(root); + root.didChange = true; + const children = root.children; + for (let i = 0; i < children.length; i++) { + this.addChild(children[i]); + } + } + get localTransform() { + return this.root.localTransform; + } + addRenderGroupChild(renderGroupChild) { + if (renderGroupChild.renderGroupParent) { + renderGroupChild.renderGroupParent._removeRenderGroupChild(renderGroupChild); + } + renderGroupChild.renderGroupParent = this; + this.renderGroupChildren.push(renderGroupChild); + } + _removeRenderGroupChild(renderGroupChild) { + const index = this.renderGroupChildren.indexOf(renderGroupChild); + if (index > -1) { + this.renderGroupChildren.splice(index, 1); + } + renderGroupChild.renderGroupParent = null; + } + addChild(child) { + this.structureDidChange = true; + child.parentRenderGroup = this; + child.updateTick = -1; + if (child.parent === this.root) { + child.relativeRenderGroupDepth = 1; + } else { + child.relativeRenderGroupDepth = child.parent.relativeRenderGroupDepth + 1; + } + child.didChange = true; + this.onChildUpdate(child); + if (child.renderGroup) { + this.addRenderGroupChild(child.renderGroup); + return; + } + if (child._onRender) + this.addOnRender(child); + const children = child.children; + for (let i = 0; i < children.length; i++) { + this.addChild(children[i]); + } + } + removeChild(child) { + this.structureDidChange = true; + if (child._onRender) { + if (!child.renderGroup) { + this.removeOnRender(child); + } + } + child.parentRenderGroup = null; + if (child.renderGroup) { + this._removeRenderGroupChild(child.renderGroup); + return; + } + const children = child.children; + for (let i = 0; i < children.length; i++) { + this.removeChild(children[i]); + } + } + removeChildren(children) { + for (let i = 0; i < children.length; i++) { + this.removeChild(children[i]); + } + } + onChildUpdate(child) { + let childrenToUpdate = this.childrenToUpdate[child.relativeRenderGroupDepth]; + if (!childrenToUpdate) { + childrenToUpdate = this.childrenToUpdate[child.relativeRenderGroupDepth] = { + index: 0, + list: [] + }; + } + childrenToUpdate.list[childrenToUpdate.index++] = child; + } + // SHOULD THIS BE HERE? + updateRenderable(container) { + if (container.globalDisplayStatus < 7) + return; + container.didViewUpdate = false; + this.instructionSet.renderPipes[container.renderPipeId].updateRenderable(container); + } + onChildViewUpdate(child) { + this.childrenRenderablesToUpdate.list[this.childrenRenderablesToUpdate.index++] = child; + } + get isRenderable() { + return this.root.localDisplayStatus === 7 && this.worldAlpha > 0; + } + /** + * adding a container to the onRender list will make sure the user function + * passed in to the user defined 'onRender` callBack + * @param container - the container to add to the onRender list + */ + addOnRender(container) { + this._onRenderContainers.push(container); + } + removeOnRender(container) { + this._onRenderContainers.splice(this._onRenderContainers.indexOf(container), 1); + } + runOnRender() { + for (let i = 0; i < this._onRenderContainers.length; i++) { + this._onRenderContainers[i]._onRender(); + } + } + destroy() { + this.renderGroupParent = null; + this.root = null; + this.childrenRenderablesToUpdate = null; + this.childrenToUpdate = null; + this.renderGroupChildren = null; + this._onRenderContainers = null; + this.instructionSet = null; + } + getChildren(out = []) { + const children = this.root.children; + for (let i = 0; i < children.length; i++) { + this._getChildren(children[i], out); + } + return out; + } + _getChildren(container, out = []) { + out.push(container); + if (container.renderGroup) + return out; + const children = container.children; + for (let i = 0; i < children.length; i++) { + this._getChildren(children[i], out); + } + return out; + } + } + + "use strict"; + function assignWithIgnore(target, options, ignore = {}) { + for (const key in options) { + if (!ignore[key] && options[key] !== void 0) { + target[key] = options[key]; + } + } + } + + "use strict"; + const defaultSkew = new ObservablePoint(null); + const defaultPivot = new ObservablePoint(null); + const defaultScale = new ObservablePoint(null, 1, 1); + const UPDATE_COLOR = 1; + const UPDATE_BLEND = 2; + const UPDATE_VISIBLE = 4; + const UPDATE_TRANSFORM = 8; + class Container extends EventEmitter { + constructor(options = {}) { + var _a, _b; + super(); + /** @private */ + this.uid = uid("renderable"); + /** @private */ + this._updateFlags = 15; + // the render group this container owns + /** @private */ + this.renderGroup = null; + // the render group this container belongs to + /** @private */ + this.parentRenderGroup = null; + // the index of the container in the render group + /** @private */ + this.parentRenderGroupIndex = 0; + // set to true if the container has changed. It is reset once the changes have been applied + // by the transform system + // its here to stop ensure that when things change, only one update gets registers with the transform system + /** @private */ + this.didChange = false; + // same as above, but for the renderable + /** @private */ + this.didViewUpdate = false; + // how deep is the container relative to its render group.. + // unless the element is the root render group - it will be relative to its parent + /** @private */ + this.relativeRenderGroupDepth = 0; + /** + * The array of children of this container. + * @readonly + */ + this.children = []; + /** The display object container that contains this display object. */ + this.parent = null; + // used internally for changing up the render order.. mainly for masks and filters + // TODO setting this should cause a rebuild?? + /** @private */ + this.includeInBuild = true; + /** @private */ + this.measurable = true; + /** @private */ + this.isSimple = true; + // / /////////////Transform related props////////////// + // used by the transform system to check if a container needs to be updated that frame + // if the tick matches the current transform system tick, it is not updated again + /** + * @internal + * @ignore + */ + this.updateTick = -1; + /** + * Current transform of the object based on local factors: position, scale, other stuff. + * @readonly + */ + this.localTransform = new Matrix(); + /** + * The relative group transform is a transform relative to the render group it belongs too. It will include all parent + * transforms and up to the render group (think of it as kind of like a stage - but the stage can be nested). + * If this container is is self a render group matrix will be relative to its parent render group + * @readonly + */ + this.relativeGroupTransform = new Matrix(); + /** + * The group transform is a transform relative to the render group it belongs too. + * If this container is render group then this will be an identity matrix. other wise it + * will be the same as the relativeGroupTransform. + * Use this value when actually rendering things to the screen + * @readonly + */ + this.groupTransform = this.relativeGroupTransform; + /** If the object has been destroyed via destroy(). If true, it should not be used. */ + this.destroyed = false; + // transform data.. + /** + * The coordinate of the object relative to the local coordinates of the parent. + * @internal + * @ignore + */ + this._position = new ObservablePoint(this, 0, 0); + /** + * The scale factor of the object. + * @internal + * @ignore + */ + this._scale = defaultScale; + /** + * The pivot point of the container that it rotates around. + * @internal + * @ignore + */ + this._pivot = defaultPivot; + /** + * The skew amount, on the x and y axis. + * @internal + * @ignore + */ + this._skew = defaultSkew; + /** + * The X-coordinate value of the normalized local X axis, + * the first column of the local transformation matrix without a scale. + * @internal + * @ignore + */ + this._cx = 1; + /** + * The Y-coordinate value of the normalized local X axis, + * the first column of the local transformation matrix without a scale. + * @internal + * @ignore + */ + this._sx = 0; + /** + * The X-coordinate value of the normalized local Y axis, + * the second column of the local transformation matrix without a scale. + * @internal + * @ignore + */ + this._cy = 0; + /** + * The Y-coordinate value of the normalized local Y axis, + * the second column of the local transformation matrix without a scale. + * @internal + * @ignore + */ + this._sy = 1; + /** + * The rotation amount. + * @internal + * @ignore + */ + this._rotation = 0; + // / COLOR related props ////////////// + // color stored as ABGR + this.localColor = 16777215; + this.localAlpha = 1; + this.groupAlpha = 1; + // A + this.groupColor = 16777215; + // BGR + this.groupColorAlpha = 4294967295; + // ABGR + // / BLEND related props ////////////// + /** + * @internal + * @ignore + */ + this.localBlendMode = "inherit"; + /** + * @internal + * @ignore + */ + this.groupBlendMode = "normal"; + // / VISIBILITY related props ////////////// + // visibility + // 0b11 + // first bit is visible, second bit is renderable + /** + * This property holds three bits: culled, visible, renderable + * the third bit represents culling (0 = culled, 1 = not culled) 0b100 + * the second bit represents visibility (0 = not visible, 1 = visible) 0b010 + * the first bit represents renderable (0 = renderable, 1 = not renderable) 0b001 + * @internal + * @ignore + */ + this.localDisplayStatus = 7; + // 0b11 | 0b10 | 0b01 | 0b00 + /** + * @internal + * @ignore + */ + this.globalDisplayStatus = 7; + /** + * A value that increments each time the container is modified + * the first 12 bits represent the container changes (eg transform, alpha, visible etc) + * the second 12 bits represent: + * - for view changes (eg texture swap, geometry change etc) + * - containers changes (eg children added, removed etc) + * + * view container + * [000000000000][00000000000] + * @ignore + */ + this._didChangeId = 0; + /** + * property that tracks if the container transform has changed + * @ignore + */ + this._didLocalTransformChangeId = -1; + assignWithIgnore(this, options, { + children: true, + parent: true, + effects: true + }); + (_a = options.children) == null ? void 0 : _a.forEach((child) => this.addChild(child)); + this.effects = []; + (_b = options.parent) == null ? void 0 : _b.addChild(this); + } + /** + * Mixes all enumerable properties and methods from a source object to Container. + * @param source - The source of properties and methods to mix in. + */ + static mixin(source) { + Object.defineProperties(Container.prototype, Object.getOwnPropertyDescriptors(source)); + } + /** + * Adds one or more children to the container. + * + * Multiple items can be added like so: `myContainer.addChild(thingOne, thingTwo, thingThree)` + * @param {...Container} children - The Container(s) to add to the container + * @returns {Container} - The first child that was added. + */ + addChild(...children) { + if (!this.allowChildren) { + deprecation(v8_0_0, "addChild: Only Containers will be allowed to add children in v8.0.0"); + } + if (children.length > 1) { + for (let i = 0; i < children.length; i++) { + this.addChild(children[i]); + } + return children[0]; + } + const child = children[0]; + if (child.parent === this) { + this.children.splice(this.children.indexOf(child), 1); + this.children.push(child); + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + return child; + } + if (child.parent) { + child.parent.removeChild(child); + } + this.children.push(child); + if (this.sortableChildren) + this.sortDirty = true; + child.parent = this; + child.didChange = true; + child.didViewUpdate = false; + child._updateFlags = 15; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.addChild(child); + } + this.emit("childAdded", child, this, this.children.length - 1); + child.emit("added", this); + this._didChangeId += 1 << 12; + if (child._zIndex !== 0) { + child.depthOfChildModified(); + } + return child; + } + /** + * Removes one or more children from the container. + * @param {...Container} children - The Container(s) to remove + * @returns {Container} The first child that was removed. + */ + removeChild(...children) { + if (children.length > 1) { + for (let i = 0; i < children.length; i++) { + this.removeChild(children[i]); + } + return children[0]; + } + const child = children[0]; + const index = this.children.indexOf(child); + if (index > -1) { + this._didChangeId += 1 << 12; + this.children.splice(index, 1); + if (this.renderGroup) { + this.renderGroup.removeChild(child); + } else if (this.parentRenderGroup) { + this.parentRenderGroup.removeChild(child); + } + child.parent = null; + this.emit("childRemoved", child, this, index); + child.emit("removed", this); + } + return child; + } + /** @ignore */ + _onUpdate(point) { + if (point) { + if (point === this._skew) { + this._updateSkew(); + } + } + this._didChangeId++; + if (this.didChange) + return; + this.didChange = true; + if (this.parentRenderGroup) { + this.parentRenderGroup.onChildUpdate(this); + } + } + set isRenderGroup(value) { + if (this.renderGroup && value === false) { + throw new Error("[Pixi] cannot undo a render group just yet"); + } + if (value) { + this.enableRenderGroup(); + } + } + /** + * Returns true if this container is a render group. + * This means that it will be rendered as a separate pass, with its own set of instructions + */ + get isRenderGroup() { + return !!this.renderGroup; + } + /** This enables the container to be rendered as a render group. */ + enableRenderGroup() { + if (this.renderGroup) + return; + const parentRenderGroup = this.parentRenderGroup; + if (parentRenderGroup) { + parentRenderGroup.removeChild(this); + } + this.renderGroup = new RenderGroup(this); + if (parentRenderGroup) { + parentRenderGroup.addChild(this); + } + this._updateIsSimple(); + this.groupTransform = Matrix.IDENTITY; + } + /** @ignore */ + _updateIsSimple() { + this.isSimple = !this.renderGroup && this.effects.length === 0; + } + /** + * Current transform of the object based on world (parent) factors. + * @readonly + */ + get worldTransform() { + this._worldTransform || (this._worldTransform = new Matrix()); + if (this.renderGroup) { + this._worldTransform.copyFrom(this.renderGroup.worldTransform); + } else if (this.parentRenderGroup) { + this._worldTransform.appendFrom(this.relativeGroupTransform, this.parentRenderGroup.worldTransform); + } + return this._worldTransform; + } + // / ////// transform related stuff + /** + * The position of the container on the x axis relative to the local coordinates of the parent. + * An alias to position.x + */ + get x() { + return this._position.x; + } + set x(value) { + this._position.x = value; + } + /** + * The position of the container on the y axis relative to the local coordinates of the parent. + * An alias to position.y + */ + get y() { + return this._position.y; + } + set y(value) { + this._position.y = value; + } + /** + * The coordinate of the object relative to the local coordinates of the parent. + * @since 4.0.0 + */ + get position() { + return this._position; + } + set position(value) { + this._position.copyFrom(value); + } + /** + * The rotation of the object in radians. + * 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees. + */ + get rotation() { + return this._rotation; + } + set rotation(value) { + if (this._rotation !== value) { + this._rotation = value; + this._onUpdate(this._skew); + } + } + /** + * The angle of the object in degrees. + * 'rotation' and 'angle' have the same effect on a display object; rotation is in radians, angle is in degrees. + */ + get angle() { + return this.rotation * RAD_TO_DEG; + } + set angle(value) { + this.rotation = value * DEG_TO_RAD; + } + /** + * The center of rotation, scaling, and skewing for this display object in its local space. The `position` + * is the projection of `pivot` in the parent's local space. + * + * By default, the pivot is the origin (0, 0). + * @since 4.0.0 + */ + get pivot() { + if (this._pivot === defaultPivot) { + this._pivot = new ObservablePoint(this, 0, 0); + } + return this._pivot; + } + set pivot(value) { + if (this._pivot === defaultPivot) { + this._pivot = new ObservablePoint(this, 0, 0); + } + typeof value === "number" ? this._pivot.set(value) : this._pivot.copyFrom(value); + } + /** + * The skew factor for the object in radians. + * @since 4.0.0 + */ + get skew() { + if (this._skew === defaultSkew) { + this._skew = new ObservablePoint(this, 0, 0); + } + return this._skew; + } + set skew(value) { + if (this._skew === defaultSkew) { + this._skew = new ObservablePoint(this, 0, 0); + } + this._skew.copyFrom(value); + } + /** + * The scale factors of this object along the local coordinate axes. + * + * The default scale is (1, 1). + * @since 4.0.0 + */ + get scale() { + if (this._scale === defaultScale) { + this._scale = new ObservablePoint(this, 1, 1); + } + return this._scale; + } + set scale(value) { + if (this._scale === defaultScale) { + this._scale = new ObservablePoint(this, 0, 0); + } + typeof value === "number" ? this._scale.set(value) : this._scale.copyFrom(value); + } + /** + * The width of the Container, setting this will actually modify the scale to achieve the value set. + * @memberof scene.Container# + */ + get width() { + return Math.abs(this.scale.x * this.getLocalBounds().width); + } + set width(value) { + const localWidth = this.getLocalBounds().width; + this._setWidth(value, localWidth); + } + /** + * The height of the Container, setting this will actually modify the scale to achieve the value set. + * @memberof scene.Container# + */ + get height() { + return Math.abs(this.scale.y * this.getLocalBounds().height); + } + set height(value) { + const localHeight = this.getLocalBounds().height; + this._setHeight(value, localHeight); + } + /** + * Retrieves the size of the container as a [Size]{@link Size} object. + * This is faster than get the width and height separately. + * @param out - Optional object to store the size in. + * @returns - The size of the container. + * @memberof scene.Container# + */ + getSize(out) { + if (!out) { + out = {}; + } + const bounds = this.getLocalBounds(); + out.width = Math.abs(this.scale.x * bounds.width); + out.height = Math.abs(this.scale.y * bounds.height); + return out; + } + /** + * Sets the size of the container to the specified width and height. + * This is faster than setting the width and height separately. + * @param value - This can be either a number or a [Size]{@link Size} object. + * @param height - The height to set. Defaults to the value of `width` if not provided. + * @memberof scene.Container# + */ + setSize(value, height) { + var _a; + const size = this.getLocalBounds(); + let convertedWidth; + let convertedHeight; + if (typeof value !== "object") { + convertedWidth = value; + convertedHeight = height != null ? height : value; + } else { + convertedWidth = value.width; + convertedHeight = (_a = value.height) != null ? _a : value.width; + } + if (convertedWidth !== void 0) { + this._setWidth(convertedWidth, size.width); + } + if (convertedHeight !== void 0) { + this._setHeight(convertedHeight, size.height); + } + } + /** Called when the skew or the rotation changes. */ + _updateSkew() { + const rotation = this._rotation; + const skew = this._skew; + this._cx = Math.cos(rotation + skew._y); + this._sx = Math.sin(rotation + skew._y); + this._cy = -Math.sin(rotation - skew._x); + this._sy = Math.cos(rotation - skew._x); + } + /** + * Updates the transform properties of the container (accepts partial values). + * @param {object} opts - The options for updating the transform. + * @param {number} opts.x - The x position of the container. + * @param {number} opts.y - The y position of the container. + * @param {number} opts.scaleX - The scale factor on the x-axis. + * @param {number} opts.scaleY - The scale factor on the y-axis. + * @param {number} opts.rotation - The rotation of the container, in radians. + * @param {number} opts.skewX - The skew factor on the x-axis. + * @param {number} opts.skewY - The skew factor on the y-axis. + * @param {number} opts.pivotX - The x coordinate of the pivot point. + * @param {number} opts.pivotY - The y coordinate of the pivot point. + */ + updateTransform(opts) { + this.position.set( + typeof opts.x === "number" ? opts.x : this.position.x, + typeof opts.y === "number" ? opts.y : this.position.y + ); + this.scale.set( + typeof opts.scaleX === "number" ? opts.scaleX || 1 : this.scale.x, + typeof opts.scaleY === "number" ? opts.scaleY || 1 : this.scale.y + ); + this.rotation = typeof opts.rotation === "number" ? opts.rotation : this.rotation; + this.skew.set( + typeof opts.skewX === "number" ? opts.skewX : this.skew.x, + typeof opts.skewY === "number" ? opts.skewY : this.skew.y + ); + this.pivot.set( + typeof opts.pivotX === "number" ? opts.pivotX : this.pivot.x, + typeof opts.pivotY === "number" ? opts.pivotY : this.pivot.y + ); + return this; + } + /** + * Updates the local transform using the given matrix. + * @param matrix - The matrix to use for updating the transform. + */ + setFromMatrix(matrix) { + matrix.decompose(this); + } + /** Updates the local transform. */ + updateLocalTransform() { + if ((this._didLocalTransformChangeId & 15) === this._didChangeId) + return; + this._didLocalTransformChangeId = this._didChangeId; + const lt = this.localTransform; + const scale = this._scale; + const pivot = this._pivot; + const position = this._position; + const sx = scale._x; + const sy = scale._y; + const px = pivot._x; + const py = pivot._y; + lt.a = this._cx * sx; + lt.b = this._sx * sx; + lt.c = this._cy * sy; + lt.d = this._sy * sy; + lt.tx = position._x - (px * lt.a + py * lt.c); + lt.ty = position._y - (px * lt.b + py * lt.d); + } + // / ///// color related stuff + set alpha(value) { + if (value === this.localAlpha) + return; + this.localAlpha = value; + this._updateFlags |= UPDATE_COLOR; + this._onUpdate(); + } + /** The opacity of the object. */ + get alpha() { + return this.localAlpha; + } + set tint(value) { + const tempColor = Color.shared.setValue(value != null ? value : 16777215); + const bgr = tempColor.toBgrNumber(); + if (bgr === this.localColor) + return; + this.localColor = bgr; + this._updateFlags |= UPDATE_COLOR; + this._onUpdate(); + } + /** + * The tint applied to the sprite. This is a hex value. + * + * A value of 0xFFFFFF will remove any tint effect. + * @default 0xFFFFFF + */ + get tint() { + const bgr = this.localColor; + return ((bgr & 255) << 16) + (bgr & 65280) + (bgr >> 16 & 255); + } + // / //////////////// blend related stuff + set blendMode(value) { + if (this.localBlendMode === value) + return; + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + this._updateFlags |= UPDATE_BLEND; + this.localBlendMode = value; + this._onUpdate(); + } + /** + * The blend mode to be applied to the sprite. Apply a value of `'normal'` to reset the blend mode. + * @default 'normal' + */ + get blendMode() { + return this.localBlendMode; + } + // / ///////// VISIBILITY / RENDERABLE ///////////////// + /** The visibility of the object. If false the object will not be drawn, and the transform will not be updated. */ + get visible() { + return !!(this.localDisplayStatus & 2); + } + set visible(value) { + const valueNumber = value ? 1 : 0; + if ((this.localDisplayStatus & 2) >> 1 === valueNumber) + return; + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + this._updateFlags |= UPDATE_VISIBLE; + this.localDisplayStatus ^= 2; + this._onUpdate(); + } + /** @ignore */ + get culled() { + return !(this.localDisplayStatus & 4); + } + /** @ignore */ + set culled(value) { + const valueNumber = value ? 1 : 0; + if ((this.localDisplayStatus & 4) >> 2 === valueNumber) + return; + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + this._updateFlags |= UPDATE_VISIBLE; + this.localDisplayStatus ^= 4; + this._onUpdate(); + } + /** Can this object be rendered, if false the object will not be drawn but the transform will still be updated. */ + get renderable() { + return !!(this.localDisplayStatus & 1); + } + set renderable(value) { + const valueNumber = value ? 1 : 0; + if ((this.localDisplayStatus & 1) === valueNumber) + return; + this._updateFlags |= UPDATE_VISIBLE; + this.localDisplayStatus ^= 1; + if (this.parentRenderGroup) { + this.parentRenderGroup.structureDidChange = true; + } + this._onUpdate(); + } + /** Whether or not the object should be rendered. */ + get isRenderable() { + return this.localDisplayStatus === 7 && this.groupAlpha > 0; + } + /** + * Removes all internal references and listeners as well as removes children from the display list. + * Do not use a Container after calling `destroy`. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.children=false] - if set to true, all the children will have their destroy + * method called as well. 'options' will be passed on to those calls. + * @param {boolean} [options.texture=false] - Only used for children with textures e.g. Sprites. If options.children + * is set to true it should destroy the texture of the child sprite + * @param {boolean} [options.textureSource=false] - Only used for children with textures e.g. Sprites. + * If options.children is set to true it should destroy the texture source of the child sprite + * @param {boolean} [options.context=false] - Only used for children with graphicsContexts e.g. Graphics. + * If options.children is set to true it should destroy the context of the child graphics + */ + destroy(options = false) { + var _a; + if (this.destroyed) + return; + this.destroyed = true; + const oldChildren = this.removeChildren(0, this.children.length); + this.removeFromParent(); + this.parent = null; + this._maskEffect = null; + this._filterEffect = null; + this.effects = null; + this._position = null; + this._scale = null; + this._pivot = null; + this._skew = null; + this.emit("destroyed", this); + this.removeAllListeners(); + const destroyChildren = typeof options === "boolean" ? options : options == null ? void 0 : options.children; + if (destroyChildren) { + for (let i = 0; i < oldChildren.length; ++i) { + oldChildren[i].destroy(options); + } + } + (_a = this.renderGroup) == null ? void 0 : _a.destroy(); + this.renderGroup = null; + } + } + Container.mixin(childrenHelperMixin); + Container.mixin(toLocalGlobalMixin); + Container.mixin(onRenderMixin); + Container.mixin(measureMixin); + Container.mixin(effectsMixin); + Container.mixin(findMixin); + Container.mixin(sortMixin); + Container.mixin(cullingMixin); + + "use strict"; + class FederatedEvent { + /** + * @param manager - The event boundary which manages this event. Propagation can only occur + * within the boundary's jurisdiction. + */ + constructor(manager) { + /** Flags whether this event bubbles. This will take effect only if it is set before propagation. */ + this.bubbles = true; + /** @deprecated since 7.0.0 */ + this.cancelBubble = true; + /** + * Flags whether this event can be canceled using {@link FederatedEvent.preventDefault}. This is always + * false (for now). + */ + this.cancelable = false; + /** + * Flag added for compatibility with DOM {@code Event}. It is not used in the Federated Events + * API. + * @see https://dom.spec.whatwg.org/#dom-event-composed + */ + this.composed = false; + /** Flags whether the default response of the user agent was prevent through this event. */ + this.defaultPrevented = false; + /** + * The propagation phase. + * @default {@link FederatedEvent.NONE} + */ + this.eventPhase = FederatedEvent.prototype.NONE; + /** Flags whether propagation was stopped. */ + this.propagationStopped = false; + /** Flags whether propagation was immediately stopped. */ + this.propagationImmediatelyStopped = false; + /** The coordinates of the event relative to the nearest DOM layer. This is a non-standard property. */ + this.layer = new Point(); + /** The coordinates of the event relative to the DOM document. This is a non-standard property. */ + this.page = new Point(); + this.NONE = 0; + this.CAPTURING_PHASE = 1; + this.AT_TARGET = 2; + this.BUBBLING_PHASE = 3; + this.manager = manager; + } + /** @readonly */ + get layerX() { + return this.layer.x; + } + /** @readonly */ + get layerY() { + return this.layer.y; + } + /** @readonly */ + get pageX() { + return this.page.x; + } + /** @readonly */ + get pageY() { + return this.page.y; + } + /** + * Fallback for the deprecated @code{InteractionEvent.data}. + * @deprecated since 7.0.0 + */ + get data() { + return this; + } + /** The propagation path for this event. Alias for {@link EventBoundary.propagationPath}. */ + composedPath() { + if (this.manager && (!this.path || this.path[this.path.length - 1] !== this.target)) { + this.path = this.target ? this.manager.propagationPath(this.target) : []; + } + return this.path; + } + /** + * Unimplemented method included for implementing the DOM interface {@code Event}. It will throw an {@code Error}. + * @deprecated + * @param _type + * @param _bubbles + * @param _cancelable + */ + initEvent(_type, _bubbles, _cancelable) { + throw new Error("initEvent() is a legacy DOM API. It is not implemented in the Federated Events API."); + } + /** + * Unimplemented method included for implementing the DOM interface {@code UIEvent}. It will throw an {@code Error}. + * @deprecated + * @param _typeArg + * @param _bubblesArg + * @param _cancelableArg + * @param _viewArg + * @param _detailArg + */ + initUIEvent(_typeArg, _bubblesArg, _cancelableArg, _viewArg, _detailArg) { + throw new Error("initUIEvent() is a legacy DOM API. It is not implemented in the Federated Events API."); + } + /** Prevent default behavior of PixiJS and the user agent. */ + preventDefault() { + if (this.nativeEvent instanceof Event && this.nativeEvent.cancelable) { + this.nativeEvent.preventDefault(); + } + this.defaultPrevented = true; + } + /** + * Stop this event from propagating to any addition listeners, including on the + * {@link FederatedEventTarget.currentTarget currentTarget} and also the following + * event targets on the propagation path. + */ + stopImmediatePropagation() { + this.propagationImmediatelyStopped = true; + } + /** + * Stop this event from propagating to the next {@link FederatedEventTarget}. The rest of the listeners + * on the {@link FederatedEventTarget.currentTarget currentTarget} will still be notified. + */ + stopPropagation() { + this.propagationStopped = true; + } + } + + var appleIphone = /iPhone/i; + var appleIpod = /iPod/i; + var appleTablet = /iPad/i; + var appleUniversal = /\biOS-universal(?:.+)Mac\b/i; + var androidPhone = /\bAndroid(?:.+)Mobile\b/i; + var androidTablet = /Android/i; + var amazonPhone = /(?:SD4930UR|\bSilk(?:.+)Mobile\b)/i; + var amazonTablet = /Silk/i; + var windowsPhone = /Windows Phone/i; + var windowsTablet = /\bWindows(?:.+)ARM\b/i; + var otherBlackBerry = /BlackBerry/i; + var otherBlackBerry10 = /BB10/i; + var otherOpera = /Opera Mini/i; + var otherChrome = /\b(CriOS|Chrome)(?:.+)Mobile/i; + var otherFirefox = /Mobile(?:.+)Firefox\b/i; + var isAppleTabletOnIos13 = function (navigator) { + return (typeof navigator !== 'undefined' && + navigator.platform === 'MacIntel' && + typeof navigator.maxTouchPoints === 'number' && + navigator.maxTouchPoints > 1 && + typeof MSStream === 'undefined'); + }; + function createMatch(userAgent) { + return function (regex) { return regex.test(userAgent); }; + } + function isMobile$1(param) { + var nav = { + userAgent: '', + platform: '', + maxTouchPoints: 0 + }; + if (!param && typeof navigator !== 'undefined') { + nav = { + userAgent: navigator.userAgent, + platform: navigator.platform, + maxTouchPoints: navigator.maxTouchPoints || 0 + }; + } + else if (typeof param === 'string') { + nav.userAgent = param; + } + else if (param && param.userAgent) { + nav = { + userAgent: param.userAgent, + platform: param.platform, + maxTouchPoints: param.maxTouchPoints || 0 + }; + } + var userAgent = nav.userAgent; + var tmp = userAgent.split('[FBAN'); + if (typeof tmp[1] !== 'undefined') { + userAgent = tmp[0]; + } + tmp = userAgent.split('Twitter'); + if (typeof tmp[1] !== 'undefined') { + userAgent = tmp[0]; + } + var match = createMatch(userAgent); + var result = { + apple: { + phone: match(appleIphone) && !match(windowsPhone), + ipod: match(appleIpod), + tablet: !match(appleIphone) && + (match(appleTablet) || isAppleTabletOnIos13(nav)) && + !match(windowsPhone), + universal: match(appleUniversal), + device: (match(appleIphone) || + match(appleIpod) || + match(appleTablet) || + match(appleUniversal) || + isAppleTabletOnIos13(nav)) && + !match(windowsPhone) + }, + amazon: { + phone: match(amazonPhone), + tablet: !match(amazonPhone) && match(amazonTablet), + device: match(amazonPhone) || match(amazonTablet) + }, + android: { + phone: (!match(windowsPhone) && match(amazonPhone)) || + (!match(windowsPhone) && match(androidPhone)), + tablet: !match(windowsPhone) && + !match(amazonPhone) && + !match(androidPhone) && + (match(amazonTablet) || match(androidTablet)), + device: (!match(windowsPhone) && + (match(amazonPhone) || + match(amazonTablet) || + match(androidPhone) || + match(androidTablet))) || + match(/\bokhttp\b/i) + }, + windows: { + phone: match(windowsPhone), + tablet: match(windowsTablet), + device: match(windowsPhone) || match(windowsTablet) + }, + other: { + blackberry: match(otherBlackBerry), + blackberry10: match(otherBlackBerry10), + opera: match(otherOpera), + firefox: match(otherFirefox), + chrome: match(otherChrome), + device: match(otherBlackBerry) || + match(otherBlackBerry10) || + match(otherOpera) || + match(otherFirefox) || + match(otherChrome) + }, + any: false, + phone: false, + tablet: false + }; + result.any = + result.apple.device || + result.android.device || + result.windows.device || + result.other.device; + result.phone = + result.apple.phone || result.android.phone || result.windows.phone; + result.tablet = + result.apple.tablet || result.android.tablet || result.windows.tablet; + return result; + } + + "use strict"; + var _a; + const isMobileCall = (_a = isMobile$1.default) != null ? _a : isMobile$1; + const isMobile = isMobileCall(globalThis.navigator); + + "use strict"; + const KEY_CODE_TAB = 9; + const DIV_TOUCH_SIZE = 100; + const DIV_TOUCH_POS_X = 0; + const DIV_TOUCH_POS_Y = 0; + const DIV_TOUCH_ZINDEX = 2; + const DIV_HOOK_SIZE = 1; + const DIV_HOOK_POS_X = -1e3; + const DIV_HOOK_POS_Y = -1e3; + const DIV_HOOK_ZINDEX = 2; + class AccessibilitySystem { + // 2fps + // eslint-disable-next-line jsdoc/require-param + /** + * @param {WebGLRenderer|WebGPURenderer} renderer - A reference to the current renderer + */ + constructor(renderer, _mobileInfo = isMobile) { + this._mobileInfo = _mobileInfo; + /** Setting this to true will visually show the divs. */ + this.debug = false; + /** Internal variable, see isActive getter. */ + this._isActive = false; + /** Internal variable, see isMobileAccessibility getter. */ + this._isMobileAccessibility = false; + /** A simple pool for storing divs. */ + this._pool = []; + /** This is a tick used to check if an object is no longer being rendered. */ + this._renderId = 0; + /** The array of currently active accessible items. */ + this._children = []; + /** Count to throttle div updates on android devices. */ + this._androidUpdateCount = 0; + /** The frequency to update the div elements. */ + this._androidUpdateFrequency = 500; + this._hookDiv = null; + if (_mobileInfo.tablet || _mobileInfo.phone) { + this._createTouchHook(); + } + const div = document.createElement("div"); + div.style.width = `${DIV_TOUCH_SIZE}px`; + div.style.height = `${DIV_TOUCH_SIZE}px`; + div.style.position = "absolute"; + div.style.top = `${DIV_TOUCH_POS_X}px`; + div.style.left = `${DIV_TOUCH_POS_Y}px`; + div.style.zIndex = DIV_TOUCH_ZINDEX.toString(); + this._div = div; + this._renderer = renderer; + this._onKeyDown = this._onKeyDown.bind(this); + this._onMouseMove = this._onMouseMove.bind(this); + globalThis.addEventListener("keydown", this._onKeyDown, false); + } + /** + * Value of `true` if accessibility is currently active and accessibility layers are showing. + * @member {boolean} + * @readonly + */ + get isActive() { + return this._isActive; + } + /** + * Value of `true` if accessibility is enabled for touch devices. + * @member {boolean} + * @readonly + */ + get isMobileAccessibility() { + return this._isMobileAccessibility; + } + get hookDiv() { + return this._hookDiv; + } + /** + * Creates the touch hooks. + * @private + */ + _createTouchHook() { + const hookDiv = document.createElement("button"); + hookDiv.style.width = `${DIV_HOOK_SIZE}px`; + hookDiv.style.height = `${DIV_HOOK_SIZE}px`; + hookDiv.style.position = "absolute"; + hookDiv.style.top = `${DIV_HOOK_POS_X}px`; + hookDiv.style.left = `${DIV_HOOK_POS_Y}px`; + hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString(); + hookDiv.style.backgroundColor = "#FF0000"; + hookDiv.title = "select to enable accessibility for this content"; + hookDiv.addEventListener("focus", () => { + this._isMobileAccessibility = true; + this._activate(); + this._destroyTouchHook(); + }); + document.body.appendChild(hookDiv); + this._hookDiv = hookDiv; + } + /** + * Destroys the touch hooks. + * @private + */ + _destroyTouchHook() { + if (!this._hookDiv) { + return; + } + document.body.removeChild(this._hookDiv); + this._hookDiv = null; + } + /** + * Activating will cause the Accessibility layer to be shown. + * This is called when a user presses the tab key. + * @private + */ + _activate() { + var _a; + if (this._isActive) { + return; + } + this._isActive = true; + globalThis.document.addEventListener("mousemove", this._onMouseMove, true); + globalThis.removeEventListener("keydown", this._onKeyDown, false); + this._renderer.runners.postrender.add(this); + (_a = this._renderer.view.canvas.parentNode) == null ? void 0 : _a.appendChild(this._div); + } + /** + * Deactivating will cause the Accessibility layer to be hidden. + * This is called when a user moves the mouse. + * @private + */ + _deactivate() { + var _a; + if (!this._isActive || this._isMobileAccessibility) { + return; + } + this._isActive = false; + globalThis.document.removeEventListener("mousemove", this._onMouseMove, true); + globalThis.addEventListener("keydown", this._onKeyDown, false); + this._renderer.runners.postrender.remove(this); + (_a = this._div.parentNode) == null ? void 0 : _a.removeChild(this._div); + } + /** + * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer. + * @private + * @param {Container} container - The Container to check. + */ + _updateAccessibleObjects(container) { + if (!container.visible || !container.accessibleChildren) { + return; + } + if (container.accessible && container.isInteractive()) { + if (!container._accessibleActive) { + this._addChild(container); + } + container._renderId = this._renderId; + } + const children = container.children; + if (children) { + for (let i = 0; i < children.length; i++) { + this._updateAccessibleObjects(children[i]); + } + } + } + /** + * Runner init called, view is available at this point. + * @ignore + */ + init(options) { + var _a; + this.debug = (_a = options == null ? void 0 : options.debug) != null ? _a : this.debug; + this._renderer.runners.postrender.remove(this); + } + /** + * Runner postrender was called, ensure that all divs are mapped correctly to their Containers. + * Only fires while active. + * @ignore + */ + postrender() { + const now = performance.now(); + if (this._mobileInfo.android.device && now < this._androidUpdateCount) { + return; + } + this._androidUpdateCount = now + this._androidUpdateFrequency; + if (!this._renderer.renderingToScreen || !this._renderer.view.canvas) { + return; + } + if (this._renderer.lastObjectRendered) { + this._updateAccessibleObjects(this._renderer.lastObjectRendered); + } + const { x, y, width, height } = this._renderer.view.canvas.getBoundingClientRect(); + const { width: viewWidth, height: viewHeight, resolution } = this._renderer; + const sx = width / viewWidth * resolution; + const sy = height / viewHeight * resolution; + let div = this._div; + div.style.left = `${x}px`; + div.style.top = `${y}px`; + div.style.width = `${viewWidth}px`; + div.style.height = `${viewHeight}px`; + for (let i = 0; i < this._children.length; i++) { + const child = this._children[i]; + if (child._renderId !== this._renderId) { + child._accessibleActive = false; + removeItems(this._children, i, 1); + this._div.removeChild(child._accessibleDiv); + this._pool.push(child._accessibleDiv); + child._accessibleDiv = null; + i--; + } else { + div = child._accessibleDiv; + let hitArea = child.hitArea; + const wt = child.worldTransform; + if (child.hitArea) { + div.style.left = `${(wt.tx + hitArea.x * wt.a) * sx}px`; + div.style.top = `${(wt.ty + hitArea.y * wt.d) * sy}px`; + div.style.width = `${hitArea.width * wt.a * sx}px`; + div.style.height = `${hitArea.height * wt.d * sy}px`; + } else { + hitArea = child.getBounds().rectangle; + this._capHitArea(hitArea); + div.style.left = `${hitArea.x * sx}px`; + div.style.top = `${hitArea.y * sy}px`; + div.style.width = `${hitArea.width * sx}px`; + div.style.height = `${hitArea.height * sy}px`; + if (div.title !== child.accessibleTitle && child.accessibleTitle !== null) { + div.title = child.accessibleTitle || ""; + } + if (div.getAttribute("aria-label") !== child.accessibleHint && child.accessibleHint !== null) { + div.setAttribute("aria-label", child.accessibleHint || ""); + } + } + if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) { + div.title = child.accessibleTitle || ""; + div.tabIndex = child.tabIndex; + if (this.debug) { + this._updateDebugHTML(div); + } + } + } + } + this._renderId++; + } + /** + * private function that will visually add the information to the + * accessibility div + * @param {HTMLElement} div - + */ + _updateDebugHTML(div) { + div.innerHTML = `type: ${div.type}
title : ${div.title}
tabIndex: ${div.tabIndex}`; + } + /** + * Adjust the hit area based on the bounds of a display object + * @param {Rectangle} hitArea - Bounds of the child + */ + _capHitArea(hitArea) { + if (hitArea.x < 0) { + hitArea.width += hitArea.x; + hitArea.x = 0; + } + if (hitArea.y < 0) { + hitArea.height += hitArea.y; + hitArea.y = 0; + } + const { width: viewWidth, height: viewHeight } = this._renderer; + if (hitArea.x + hitArea.width > viewWidth) { + hitArea.width = viewWidth - hitArea.x; + } + if (hitArea.y + hitArea.height > viewHeight) { + hitArea.height = viewHeight - hitArea.y; + } + } + /** + * Adds a Container to the accessibility manager + * @private + * @param {Container} container - The child to make accessible. + */ + _addChild(container) { + let div = this._pool.pop(); + if (!div) { + div = document.createElement("button"); + div.style.width = `${DIV_TOUCH_SIZE}px`; + div.style.height = `${DIV_TOUCH_SIZE}px`; + div.style.backgroundColor = this.debug ? "rgba(255,255,255,0.5)" : "transparent"; + div.style.position = "absolute"; + div.style.zIndex = DIV_TOUCH_ZINDEX.toString(); + div.style.borderStyle = "none"; + if (navigator.userAgent.toLowerCase().includes("chrome")) { + div.setAttribute("aria-live", "off"); + } else { + div.setAttribute("aria-live", "polite"); + } + if (navigator.userAgent.match(/rv:.*Gecko\//)) { + div.setAttribute("aria-relevant", "additions"); + } else { + div.setAttribute("aria-relevant", "text"); + } + div.addEventListener("click", this._onClick.bind(this)); + div.addEventListener("focus", this._onFocus.bind(this)); + div.addEventListener("focusout", this._onFocusOut.bind(this)); + } + div.style.pointerEvents = container.accessiblePointerEvents; + div.type = container.accessibleType; + if (container.accessibleTitle && container.accessibleTitle !== null) { + div.title = container.accessibleTitle; + } else if (!container.accessibleHint || container.accessibleHint === null) { + div.title = `container ${container.tabIndex}`; + } + if (container.accessibleHint && container.accessibleHint !== null) { + div.setAttribute("aria-label", container.accessibleHint); + } + if (this.debug) { + this._updateDebugHTML(div); + } + container._accessibleActive = true; + container._accessibleDiv = div; + div.container = container; + this._children.push(container); + this._div.appendChild(container._accessibleDiv); + container._accessibleDiv.tabIndex = container.tabIndex; + } + /** + * Dispatch events with the EventSystem. + * @param e + * @param type + * @private + */ + _dispatchEvent(e, type) { + const { container: target } = e.target; + const boundary = this._renderer.events.rootBoundary; + const event = Object.assign(new FederatedEvent(boundary), { target }); + boundary.rootTarget = this._renderer.lastObjectRendered; + type.forEach((type2) => boundary.dispatchEvent(event, type2)); + } + /** + * Maps the div button press to pixi's EventSystem (click) + * @private + * @param {MouseEvent} e - The click event. + */ + _onClick(e) { + this._dispatchEvent(e, ["click", "pointertap", "tap"]); + } + /** + * Maps the div focus events to pixi's EventSystem (mouseover) + * @private + * @param {FocusEvent} e - The focus event. + */ + _onFocus(e) { + if (!e.target.getAttribute("aria-live")) { + e.target.setAttribute("aria-live", "assertive"); + } + this._dispatchEvent(e, ["mouseover"]); + } + /** + * Maps the div focus events to pixi's EventSystem (mouseout) + * @private + * @param {FocusEvent} e - The focusout event. + */ + _onFocusOut(e) { + if (!e.target.getAttribute("aria-live")) { + e.target.setAttribute("aria-live", "polite"); + } + this._dispatchEvent(e, ["mouseout"]); + } + /** + * Is called when a key is pressed + * @private + * @param {KeyboardEvent} e - The keydown event. + */ + _onKeyDown(e) { + if (e.keyCode !== KEY_CODE_TAB) { + return; + } + this._activate(); + } + /** + * Is called when the mouse moves across the renderer element + * @private + * @param {MouseEvent} e - The mouse event. + */ + _onMouseMove(e) { + if (e.movementX === 0 && e.movementY === 0) { + return; + } + this._deactivate(); + } + /** Destroys the accessibility manager */ + destroy() { + this._destroyTouchHook(); + this._div = null; + globalThis.document.removeEventListener("mousemove", this._onMouseMove, true); + globalThis.removeEventListener("keydown", this._onKeyDown); + this._pool = null; + this._children = null; + this._renderer = null; + } + } + /** @ignore */ + AccessibilitySystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "accessibility" + }; + + "use strict"; + const accessibilityTarget = { + /** + * Flag for if the object is accessible. If true AccessibilityManager will overlay a + * shadow div with attributes set + * @member {boolean} + * @memberof scene.Container# + */ + accessible: false, + /** + * Sets the title attribute of the shadow div + * If accessibleTitle AND accessibleHint has not been this will default to 'container [tabIndex]' + * @member {string} + * @memberof scene.Container# + */ + accessibleTitle: null, + /** + * Sets the aria-label attribute of the shadow div + * @member {string} + * @memberof scene.Container# + */ + accessibleHint: null, + /** + * @member {number} + * @memberof scene.Container# + * @todo Needs docs. + */ + tabIndex: 0, + /** + * @member {boolean} + * @memberof scene.Container# + * @private + */ + _accessibleActive: false, + /** + * @memberof scene.Container# + * @private + */ + _accessibleDiv: null, + /** + * Specify the type of div the accessible layer is. Screen readers treat the element differently + * depending on this type. Defaults to button. + * @member {string} + * @memberof scene.Container# + * @default 'button' + */ + accessibleType: "button", + /** + * Specify the pointer-events the accessible div will use + * Defaults to auto. + * @type {PointerEvents} + * @memberof scene.Container# + * @default 'auto' + */ + accessiblePointerEvents: "auto", + /** + * Setting to false will prevent any children inside this container to + * be accessible. Defaults to true. + * @member {boolean} + * @memberof scene.Container# + * @default true + */ + accessibleChildren: true, + /** + * @member {number} + * @memberof scene.Container# + * @private + */ + _renderId: -1 + }; + + "use strict"; + extensions.add(AccessibilitySystem); + Container.mixin(accessibilityTarget); + + "use strict"; + class ResizePlugin { + /** + * Initialize the plugin with scope of application instance + * @static + * @private + * @param {object} [options] - See application options + */ + static init(options) { + Object.defineProperty( + this, + "resizeTo", + /** + * The HTML element or window to automatically resize the + * renderer's view element to match width and height. + * @member {Window|HTMLElement} + * @name resizeTo + * @memberof app.Application# + */ + { + set(dom) { + globalThis.removeEventListener("resize", this.queueResize); + this._resizeTo = dom; + if (dom) { + globalThis.addEventListener("resize", this.queueResize); + this.resize(); + } + }, + get() { + return this._resizeTo; + } + } + ); + this.queueResize = () => { + if (!this._resizeTo) { + return; + } + this._cancelResize(); + this._resizeId = requestAnimationFrame(() => this.resize()); + }; + this._cancelResize = () => { + if (this._resizeId) { + cancelAnimationFrame(this._resizeId); + this._resizeId = null; + } + }; + this.resize = () => { + if (!this._resizeTo) { + return; + } + this._cancelResize(); + let width; + let height; + if (this._resizeTo === globalThis.window) { + width = globalThis.innerWidth; + height = globalThis.innerHeight; + } else { + const { clientWidth, clientHeight } = this._resizeTo; + width = clientWidth; + height = clientHeight; + } + this.renderer.resize(width, height); + this.render(); + }; + this._resizeId = null; + this._resizeTo = null; + this.resizeTo = options.resizeTo || null; + } + /** + * Clean up the ticker, scoped to application + * @static + * @private + */ + static destroy() { + globalThis.removeEventListener("resize", this.queueResize); + this._cancelResize(); + this._cancelResize = null; + this.queueResize = null; + this.resizeTo = null; + this.resize = null; + } + } + /** @ignore */ + ResizePlugin.extension = ExtensionType.Application; + + "use strict"; + var UPDATE_PRIORITY = /* @__PURE__ */ ((UPDATE_PRIORITY2) => { + UPDATE_PRIORITY2[UPDATE_PRIORITY2["INTERACTION"] = 50] = "INTERACTION"; + UPDATE_PRIORITY2[UPDATE_PRIORITY2["HIGH"] = 25] = "HIGH"; + UPDATE_PRIORITY2[UPDATE_PRIORITY2["NORMAL"] = 0] = "NORMAL"; + UPDATE_PRIORITY2[UPDATE_PRIORITY2["LOW"] = -25] = "LOW"; + UPDATE_PRIORITY2[UPDATE_PRIORITY2["UTILITY"] = -50] = "UTILITY"; + return UPDATE_PRIORITY2; + })(UPDATE_PRIORITY || {}); + + "use strict"; + class TickerListener { + /** + * Constructor + * @private + * @param fn - The listener function to be added for one update + * @param context - The listener context + * @param priority - The priority for emitting + * @param once - If the handler should fire once + */ + constructor(fn, context = null, priority = 0, once = false) { + /** The next item in chain. */ + this.next = null; + /** The previous item in chain. */ + this.previous = null; + /** `true` if this listener has been destroyed already. */ + this._destroyed = false; + this._fn = fn; + this._context = context; + this.priority = priority; + this._once = once; + } + /** + * Simple compare function to figure out if a function and context match. + * @param fn - The listener function to be added for one update + * @param context - The listener context + * @returns `true` if the listener match the arguments + */ + match(fn, context = null) { + return this._fn === fn && this._context === context; + } + /** + * Emit by calling the current function. + * @param ticker - The ticker emitting. + * @returns Next ticker + */ + emit(ticker) { + if (this._fn) { + if (this._context) { + this._fn.call(this._context, ticker); + } else { + this._fn(ticker); + } + } + const redirect = this.next; + if (this._once) { + this.destroy(true); + } + if (this._destroyed) { + this.next = null; + } + return redirect; + } + /** + * Connect to the list. + * @param previous - Input node, previous listener + */ + connect(previous) { + this.previous = previous; + if (previous.next) { + previous.next.previous = this; + } + this.next = previous.next; + previous.next = this; + } + /** + * Destroy and don't use after this. + * @param hard - `true` to remove the `next` reference, this + * is considered a hard destroy. Soft destroy maintains the next reference. + * @returns The listener to redirect while emitting or removing. + */ + destroy(hard = false) { + this._destroyed = true; + this._fn = null; + this._context = null; + if (this.previous) { + this.previous.next = this.next; + } + if (this.next) { + this.next.previous = this.previous; + } + const redirect = this.next; + this.next = hard ? null : redirect; + this.previous = null; + return redirect; + } + } + + "use strict"; + const _Ticker = class _Ticker { + constructor() { + /** + * Whether or not this ticker should invoke the method + * {@link ticker.Ticker#start|start} automatically when a listener is added. + */ + this.autoStart = false; + /** + * Scalar time value from last frame to this frame. + * This value is capped by setting {@link ticker.Ticker#minFPS|minFPS} + * and is scaled with {@link ticker.Ticker#speed|speed}. + * **Note:** The cap may be exceeded by scaling. + */ + this.deltaTime = 1; + /** + * The last time {@link ticker.Ticker#update|update} was invoked. + * This value is also reset internally outside of invoking + * update, but only when a new animation frame is requested. + * If the platform supports DOMHighResTimeStamp, + * this value will have a precision of 1 µs. + */ + this.lastTime = -1; + /** + * Factor of current {@link ticker.Ticker#deltaTime|deltaTime}. + * @example + * // Scales ticker.deltaTime to what would be + * // the equivalent of approximately 120 FPS + * ticker.speed = 2; + */ + this.speed = 1; + /** + * Whether or not this ticker has been started. + * `true` if {@link ticker.Ticker#start|start} has been called. + * `false` if {@link ticker.Ticker#stop|Stop} has been called. + * While `false`, this value may change to `true` in the + * event of {@link ticker.Ticker#autoStart|autoStart} being `true` + * and a listener is added. + */ + this.started = false; + /** Internal current frame request ID */ + this._requestId = null; + /** + * Internal value managed by minFPS property setter and getter. + * This is the maximum allowed milliseconds between updates. + */ + this._maxElapsedMS = 100; + /** + * Internal value managed by minFPS property setter and getter. + * This is the minimum allowed milliseconds between updates. + */ + this._minElapsedMS = 0; + /** If enabled, deleting is disabled.*/ + this._protected = false; + /** The last time keyframe was executed. Maintains a relatively fixed interval with the previous value. */ + this._lastFrame = -1; + this._head = new TickerListener(null, null, Infinity); + this.deltaMS = 1 / _Ticker.targetFPMS; + this.elapsedMS = 1 / _Ticker.targetFPMS; + this._tick = (time) => { + this._requestId = null; + if (this.started) { + this.update(time); + if (this.started && this._requestId === null && this._head.next) { + this._requestId = requestAnimationFrame(this._tick); + } + } + }; + } + /** + * Conditionally requests a new animation frame. + * If a frame has not already been requested, and if the internal + * emitter has listeners, a new frame is requested. + * @private + */ + _requestIfNeeded() { + if (this._requestId === null && this._head.next) { + this.lastTime = performance.now(); + this._lastFrame = this.lastTime; + this._requestId = requestAnimationFrame(this._tick); + } + } + /** + * Conditionally cancels a pending animation frame. + * @private + */ + _cancelIfNeeded() { + if (this._requestId !== null) { + cancelAnimationFrame(this._requestId); + this._requestId = null; + } + } + /** + * Conditionally requests a new animation frame. + * If the ticker has been started it checks if a frame has not already + * been requested, and if the internal emitter has listeners. If these + * conditions are met, a new frame is requested. If the ticker has not + * been started, but autoStart is `true`, then the ticker starts now, + * and continues with the previous conditions to request a new frame. + * @private + */ + _startIfPossible() { + if (this.started) { + this._requestIfNeeded(); + } else if (this.autoStart) { + this.start(); + } + } + /** + * Register a handler for tick events. Calls continuously unless + * it is removed or the ticker is stopped. + * @param fn - The listener function to be added for updates + * @param context - The listener context + * @param {number} [priority=UPDATE_PRIORITY.NORMAL] - The priority for emitting + * @returns This instance of a ticker + */ + add(fn, context, priority = UPDATE_PRIORITY.NORMAL) { + return this._addListener(new TickerListener(fn, context, priority)); + } + /** + * Add a handler for the tick event which is only execute once. + * @param fn - The listener function to be added for one update + * @param context - The listener context + * @param {number} [priority=UPDATE_PRIORITY.NORMAL] - The priority for emitting + * @returns This instance of a ticker + */ + addOnce(fn, context, priority = UPDATE_PRIORITY.NORMAL) { + return this._addListener(new TickerListener(fn, context, priority, true)); + } + /** + * Internally adds the event handler so that it can be sorted by priority. + * Priority allows certain handler (user, AnimatedSprite, Interaction) to be run + * before the rendering. + * @private + * @param listener - Current listener being added. + * @returns This instance of a ticker + */ + _addListener(listener) { + let current = this._head.next; + let previous = this._head; + if (!current) { + listener.connect(previous); + } else { + while (current) { + if (listener.priority > current.priority) { + listener.connect(previous); + break; + } + previous = current; + current = current.next; + } + if (!listener.previous) { + listener.connect(previous); + } + } + this._startIfPossible(); + return this; + } + /** + * Removes any handlers matching the function and context parameters. + * If no handlers are left after removing, then it cancels the animation frame. + * @param fn - The listener function to be removed + * @param context - The listener context to be removed + * @returns This instance of a ticker + */ + remove(fn, context) { + let listener = this._head.next; + while (listener) { + if (listener.match(fn, context)) { + listener = listener.destroy(); + } else { + listener = listener.next; + } + } + if (!this._head.next) { + this._cancelIfNeeded(); + } + return this; + } + /** + * The number of listeners on this ticker, calculated by walking through linked list + * @readonly + * @member {number} + */ + get count() { + if (!this._head) { + return 0; + } + let count = 0; + let current = this._head; + while (current = current.next) { + count++; + } + return count; + } + /** Starts the ticker. If the ticker has listeners a new animation frame is requested at this point. */ + start() { + if (!this.started) { + this.started = true; + this._requestIfNeeded(); + } + } + /** Stops the ticker. If the ticker has requested an animation frame it is canceled at this point. */ + stop() { + if (this.started) { + this.started = false; + this._cancelIfNeeded(); + } + } + /** Destroy the ticker and don't use after this. Calling this method removes all references to internal events. */ + destroy() { + if (!this._protected) { + this.stop(); + let listener = this._head.next; + while (listener) { + listener = listener.destroy(true); + } + this._head.destroy(); + this._head = null; + } + } + /** + * Triggers an update. An update entails setting the + * current {@link ticker.Ticker#elapsedMS|elapsedMS}, + * the current {@link ticker.Ticker#deltaTime|deltaTime}, + * invoking all listeners with current deltaTime, + * and then finally setting {@link ticker.Ticker#lastTime|lastTime} + * with the value of currentTime that was provided. + * This method will be called automatically by animation + * frame callbacks if the ticker instance has been started + * and listeners are added. + * @param {number} [currentTime=performance.now()] - the current time of execution + */ + update(currentTime = performance.now()) { + let elapsedMS; + if (currentTime > this.lastTime) { + elapsedMS = this.elapsedMS = currentTime - this.lastTime; + if (elapsedMS > this._maxElapsedMS) { + elapsedMS = this._maxElapsedMS; + } + elapsedMS *= this.speed; + if (this._minElapsedMS) { + const delta = currentTime - this._lastFrame | 0; + if (delta < this._minElapsedMS) { + return; + } + this._lastFrame = currentTime - delta % this._minElapsedMS; + } + this.deltaMS = elapsedMS; + this.deltaTime = this.deltaMS * _Ticker.targetFPMS; + const head = this._head; + let listener = head.next; + while (listener) { + listener = listener.emit(this); + } + if (!head.next) { + this._cancelIfNeeded(); + } + } else { + this.deltaTime = this.deltaMS = this.elapsedMS = 0; + } + this.lastTime = currentTime; + } + /** + * The frames per second at which this ticker is running. + * The default is approximately 60 in most modern browsers. + * **Note:** This does not factor in the value of + * {@link ticker.Ticker#speed|speed}, which is specific + * to scaling {@link ticker.Ticker#deltaTime|deltaTime}. + * @member {number} + * @readonly + */ + get FPS() { + return 1e3 / this.elapsedMS; + } + /** + * Manages the maximum amount of milliseconds allowed to + * elapse between invoking {@link ticker.Ticker#update|update}. + * This value is used to cap {@link ticker.Ticker#deltaTime|deltaTime}, + * but does not effect the measured value of {@link ticker.Ticker#FPS|FPS}. + * When setting this property it is clamped to a value between + * `0` and `Ticker.targetFPMS * 1000`. + * @member {number} + * @default 10 + */ + get minFPS() { + return 1e3 / this._maxElapsedMS; + } + set minFPS(fps) { + const minFPS = Math.min(this.maxFPS, fps); + const minFPMS = Math.min(Math.max(0, minFPS) / 1e3, _Ticker.targetFPMS); + this._maxElapsedMS = 1 / minFPMS; + } + /** + * Manages the minimum amount of milliseconds required to + * elapse between invoking {@link ticker.Ticker#update|update}. + * This will effect the measured value of {@link ticker.Ticker#FPS|FPS}. + * If it is set to `0`, then there is no limit; PixiJS will render as many frames as it can. + * Otherwise it will be at least `minFPS` + * @member {number} + * @default 0 + */ + get maxFPS() { + if (this._minElapsedMS) { + return Math.round(1e3 / this._minElapsedMS); + } + return 0; + } + set maxFPS(fps) { + if (fps === 0) { + this._minElapsedMS = 0; + } else { + const maxFPS = Math.max(this.minFPS, fps); + this._minElapsedMS = 1 / (maxFPS / 1e3); + } + } + /** + * The shared ticker instance used by {@link AnimatedSprite} and by + * {@link VideoResource} to update animation frames / video textures. + * + * It may also be used by {@link Application} if created with the `sharedTicker` option property set to true. + * + * The property {@link ticker.Ticker#autoStart|autoStart} is set to `true` for this instance. + * Please follow the examples for usage, including how to opt-out of auto-starting the shared ticker. + * @example + * import { Ticker } from 'pixi.js'; + * + * const ticker = Ticker.shared; + * // Set this to prevent starting this ticker when listeners are added. + * // By default this is true only for the Ticker.shared instance. + * ticker.autoStart = false; + * + * // FYI, call this to ensure the ticker is stopped. It should be stopped + * // if you have not attempted to render anything yet. + * ticker.stop(); + * + * // Call this when you are ready for a running shared ticker. + * ticker.start(); + * @example + * import { autoDetectRenderer, Container } from 'pixi.js'; + * + * // You may use the shared ticker to render... + * const renderer = autoDetectRenderer(); + * const stage = new Container(); + * document.body.appendChild(renderer.view); + * ticker.add((time) => renderer.render(stage)); + * + * // Or you can just update it manually. + * ticker.autoStart = false; + * ticker.stop(); + * const animate = (time) => { + * ticker.update(time); + * renderer.render(stage); + * requestAnimationFrame(animate); + * }; + * animate(performance.now()); + * @member {ticker.Ticker} + * @readonly + * @static + */ + static get shared() { + if (!_Ticker._shared) { + const shared = _Ticker._shared = new _Ticker(); + shared.autoStart = true; + shared._protected = true; + } + return _Ticker._shared; + } + /** + * The system ticker instance used by {@link BasePrepare} for core timing + * functionality that shouldn't usually need to be paused, unlike the `shared` + * ticker which drives visual animations and rendering which may want to be paused. + * + * The property {@link ticker.Ticker#autoStart|autoStart} is set to `true` for this instance. + * @member {ticker.Ticker} + * @readonly + * @static + */ + static get system() { + if (!_Ticker._system) { + const system = _Ticker._system = new _Ticker(); + system.autoStart = true; + system._protected = true; + } + return _Ticker._system; + } + }; + /** + * Target frames per millisecond. + * @static + */ + _Ticker.targetFPMS = 0.06; + let Ticker = _Ticker; + + "use strict"; + class TickerPlugin { + /** + * Initialize the plugin with scope of application instance + * @static + * @private + * @param {object} [options] - See application options + */ + static init(options) { + options = Object.assign({ + autoStart: true, + sharedTicker: false + }, options); + Object.defineProperty( + this, + "ticker", + { + set(ticker) { + if (this._ticker) { + this._ticker.remove(this.render, this); + } + this._ticker = ticker; + if (ticker) { + ticker.add(this.render, this, UPDATE_PRIORITY.LOW); + } + }, + get() { + return this._ticker; + } + } + ); + this.stop = () => { + this._ticker.stop(); + }; + this.start = () => { + this._ticker.start(); + }; + this._ticker = null; + this.ticker = options.sharedTicker ? Ticker.shared : new Ticker(); + if (options.autoStart) { + this.start(); + } + } + /** + * Clean up the ticker, scoped to application. + * @static + * @private + */ + static destroy() { + if (this._ticker) { + const oldTicker = this._ticker; + this.ticker = null; + oldTicker.destroy(); + } + } + } + /** @ignore */ + TickerPlugin.extension = ExtensionType.Application; + + "use strict"; + extensions.add(ResizePlugin); + extensions.add(TickerPlugin); + + "use strict"; + class EventsTickerClass { + constructor() { + /** The frequency that fake events will be fired. */ + this.interactionFrequency = 10; + this._deltaTime = 0; + this._didMove = false; + this._tickerAdded = false; + this._pauseUpdate = true; + } + /** + * Initializes the event ticker. + * @param events - The event system. + */ + init(events) { + this.removeTickerListener(); + this.events = events; + this.interactionFrequency = 10; + this._deltaTime = 0; + this._didMove = false; + this._tickerAdded = false; + this._pauseUpdate = true; + } + /** Whether to pause the update checks or not. */ + get pauseUpdate() { + return this._pauseUpdate; + } + set pauseUpdate(paused) { + this._pauseUpdate = paused; + } + /** Adds the ticker listener. */ + addTickerListener() { + if (this._tickerAdded || !this.domElement) { + return; + } + Ticker.system.add(this._tickerUpdate, this, UPDATE_PRIORITY.INTERACTION); + this._tickerAdded = true; + } + /** Removes the ticker listener. */ + removeTickerListener() { + if (!this._tickerAdded) { + return; + } + Ticker.system.remove(this._tickerUpdate, this); + this._tickerAdded = false; + } + /** Sets flag to not fire extra events when the user has already moved there mouse */ + pointerMoved() { + this._didMove = true; + } + /** Updates the state of interactive objects. */ + _update() { + if (!this.domElement || this._pauseUpdate) { + return; + } + if (this._didMove) { + this._didMove = false; + return; + } + const rootPointerEvent = this.events["_rootPointerEvent"]; + if (this.events.supportsTouchEvents && rootPointerEvent.pointerType === "touch") { + return; + } + globalThis.document.dispatchEvent(new PointerEvent("pointermove", { + clientX: rootPointerEvent.clientX, + clientY: rootPointerEvent.clientY + })); + } + /** + * Updates the state of interactive objects if at least {@link interactionFrequency} + * milliseconds have passed since the last invocation. + * + * Invoked by a throttled ticker update from {@link Ticker.system}. + * @param ticker - The throttled ticker. + */ + _tickerUpdate(ticker) { + this._deltaTime += ticker.deltaTime; + if (this._deltaTime < this.interactionFrequency) { + return; + } + this._deltaTime = 0; + this._update(); + } + } + const EventsTicker = new EventsTickerClass(); + + "use strict"; + class FederatedMouseEvent extends FederatedEvent { + constructor() { + super(...arguments); + /** The coordinates of the mouse event relative to the canvas. */ + this.client = new Point(); + /** The movement in this pointer relative to the last `mousemove` event. */ + this.movement = new Point(); + /** The offset of the pointer coordinates w.r.t. target Container in world space. This is not supported at the moment. */ + this.offset = new Point(); + /** The pointer coordinates in world space. */ + this.global = new Point(); + /** + * The pointer coordinates in the renderer's {@link Renderer.screen screen}. This has slightly + * different semantics than native PointerEvent screenX/screenY. + */ + this.screen = new Point(); + } + /** @readonly */ + get clientX() { + return this.client.x; + } + /** @readonly */ + get clientY() { + return this.client.y; + } + /** + * Alias for {@link FederatedMouseEvent.clientX this.clientX}. + * @readonly + */ + get x() { + return this.clientX; + } + /** + * Alias for {@link FederatedMouseEvent.clientY this.clientY}. + * @readonly + */ + get y() { + return this.clientY; + } + /** @readonly */ + get movementX() { + return this.movement.x; + } + /** @readonly */ + get movementY() { + return this.movement.y; + } + /** @readonly */ + get offsetX() { + return this.offset.x; + } + /** @readonly */ + get offsetY() { + return this.offset.y; + } + /** @readonly */ + get globalX() { + return this.global.x; + } + /** @readonly */ + get globalY() { + return this.global.y; + } + /** + * The pointer coordinates in the renderer's screen. Alias for {@code screen.x}. + * @readonly + */ + get screenX() { + return this.screen.x; + } + /** + * The pointer coordinates in the renderer's screen. Alias for {@code screen.y}. + * @readonly + */ + get screenY() { + return this.screen.y; + } + /** + * This will return the local coordinates of the specified container for this InteractionData + * @param {Container} container - The Container that you would like the local + * coords off + * @param {PointData} point - A Point object in which to store the value, optional (otherwise + * will create a new point) + * @param {PointData} globalPos - A Point object containing your custom global coords, optional + * (otherwise will use the current global coords) + * @returns - A point containing the coordinates of the InteractionData position relative + * to the Container + */ + getLocalPosition(container, point, globalPos) { + return container.worldTransform.applyInverse(globalPos || this.global, point); + } + /** + * Whether the modifier key was pressed when this event natively occurred. + * @param key - The modifier key. + */ + getModifierState(key) { + return "getModifierState" in this.nativeEvent && this.nativeEvent.getModifierState(key); + } + /** + * Not supported. + * @param _typeArg + * @param _canBubbleArg + * @param _cancelableArg + * @param _viewArg + * @param _detailArg + * @param _screenXArg + * @param _screenYArg + * @param _clientXArg + * @param _clientYArg + * @param _ctrlKeyArg + * @param _altKeyArg + * @param _shiftKeyArg + * @param _metaKeyArg + * @param _buttonArg + * @param _relatedTargetArg + * @deprecated since 7.0.0 + */ + // eslint-disable-next-line max-params + initMouseEvent(_typeArg, _canBubbleArg, _cancelableArg, _viewArg, _detailArg, _screenXArg, _screenYArg, _clientXArg, _clientYArg, _ctrlKeyArg, _altKeyArg, _shiftKeyArg, _metaKeyArg, _buttonArg, _relatedTargetArg) { + throw new Error("Method not implemented."); + } + } + + "use strict"; + class FederatedPointerEvent extends FederatedMouseEvent { + constructor() { + super(...arguments); + /** + * The width of the pointer's contact along the x-axis, measured in CSS pixels. + * radiusX of TouchEvents will be represented by this value. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/width + */ + this.width = 0; + /** + * The height of the pointer's contact along the y-axis, measured in CSS pixels. + * radiusY of TouchEvents will be represented by this value. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/height + */ + this.height = 0; + /** + * Indicates whether or not the pointer device that created the event is the primary pointer. + * @see https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/isPrimary + */ + this.isPrimary = false; + } + // Only included for completeness for now + getCoalescedEvents() { + if (this.type === "pointermove" || this.type === "mousemove" || this.type === "touchmove") { + return [this]; + } + return []; + } + // Only included for completeness for now + getPredictedEvents() { + throw new Error("getPredictedEvents is not supported!"); + } + } + + "use strict"; + class FederatedWheelEvent extends FederatedMouseEvent { + constructor() { + super(...arguments); + /** Units specified in pixels. */ + this.DOM_DELTA_PIXEL = 0; + /** Units specified in lines. */ + this.DOM_DELTA_LINE = 1; + /** Units specified in pages. */ + this.DOM_DELTA_PAGE = 2; + } + } + /** Units specified in pixels. */ + FederatedWheelEvent.DOM_DELTA_PIXEL = 0; + /** Units specified in lines. */ + FederatedWheelEvent.DOM_DELTA_LINE = 1; + /** Units specified in pages. */ + FederatedWheelEvent.DOM_DELTA_PAGE = 2; + + "use strict"; + const PROPAGATION_LIMIT = 2048; + const tempHitLocation = new Point(); + const tempLocalMapping = new Point(); + class EventBoundary { + /** + * @param rootTarget - The holder of the event boundary. + */ + constructor(rootTarget) { + /** + * Emits events after they were dispatched into the scene graph. + * + * This can be used for global events listening, regardless of the scene graph being used. It should + * not be used by interactive libraries for normal use. + * + * Special events that do not bubble all the way to the root target are not emitted from here, + * e.g. pointerenter, pointerleave, click. + */ + this.dispatch = new EventEmitter(); + /** + * This flag would emit `pointermove`, `touchmove`, and `mousemove` events on all Containers. + * + * The `moveOnAll` semantics mirror those of earlier versions of PixiJS. This was disabled in favor of + * the Pointer Event API's approach. + */ + this.moveOnAll = false; + /** Enables the global move events. `globalpointermove`, `globaltouchmove`, and `globalmousemove` */ + this.enableGlobalMoveEvents = true; + /** + * State object for mapping methods. + * @see EventBoundary#trackingData + */ + this.mappingState = { + trackingData: {} + }; + /** + * The event pool maps event constructors to an free pool of instances of those specific events. + * @see EventBoundary#allocateEvent + * @see EventBoundary#freeEvent + */ + this.eventPool = /* @__PURE__ */ new Map(); + /** Every interactive element gathered from the scene. Only used in `pointermove` */ + this._allInteractiveElements = []; + /** Every element that passed the hit test. Only used in `pointermove` */ + this._hitElements = []; + /** Whether or not to collect all the interactive elements from the scene. Enabled in `pointermove` */ + this._isPointerMoveEvent = false; + this.rootTarget = rootTarget; + this.hitPruneFn = this.hitPruneFn.bind(this); + this.hitTestFn = this.hitTestFn.bind(this); + this.mapPointerDown = this.mapPointerDown.bind(this); + this.mapPointerMove = this.mapPointerMove.bind(this); + this.mapPointerOut = this.mapPointerOut.bind(this); + this.mapPointerOver = this.mapPointerOver.bind(this); + this.mapPointerUp = this.mapPointerUp.bind(this); + this.mapPointerUpOutside = this.mapPointerUpOutside.bind(this); + this.mapWheel = this.mapWheel.bind(this); + this.mappingTable = {}; + this.addEventMapping("pointerdown", this.mapPointerDown); + this.addEventMapping("pointermove", this.mapPointerMove); + this.addEventMapping("pointerout", this.mapPointerOut); + this.addEventMapping("pointerleave", this.mapPointerOut); + this.addEventMapping("pointerover", this.mapPointerOver); + this.addEventMapping("pointerup", this.mapPointerUp); + this.addEventMapping("pointerupoutside", this.mapPointerUpOutside); + this.addEventMapping("wheel", this.mapWheel); + } + /** + * Adds an event mapping for the event `type` handled by `fn`. + * + * Event mappings can be used to implement additional or custom events. They take an event + * coming from the upstream scene (or directly from the {@link EventSystem}) and dispatch new downstream events + * generally trickling down and bubbling up to {@link EventBoundary.rootTarget this.rootTarget}. + * + * To modify the semantics of existing events, the built-in mapping methods of EventBoundary should be overridden + * instead. + * @param type - The type of upstream event to map. + * @param fn - The mapping method. The context of this function must be bound manually, if desired. + */ + addEventMapping(type, fn) { + if (!this.mappingTable[type]) { + this.mappingTable[type] = []; + } + this.mappingTable[type].push({ + fn, + priority: 0 + }); + this.mappingTable[type].sort((a, b) => a.priority - b.priority); + } + /** + * Dispatches the given event + * @param e - The event to dispatch. + * @param type - The type of event to dispatch. Defaults to `e.type`. + */ + dispatchEvent(e, type) { + e.propagationStopped = false; + e.propagationImmediatelyStopped = false; + this.propagate(e, type); + this.dispatch.emit(type || e.type, e); + } + /** + * Maps the given upstream event through the event boundary and propagates it downstream. + * @param e - The event to map. + */ + mapEvent(e) { + if (!this.rootTarget) { + return; + } + const mappers = this.mappingTable[e.type]; + if (mappers) { + for (let i = 0, j = mappers.length; i < j; i++) { + mappers[i].fn(e); + } + } else { + warn(`[EventBoundary]: Event mapping not defined for ${e.type}`); + } + } + /** + * Finds the Container that is the target of a event at the given coordinates. + * + * The passed (x,y) coordinates are in the world space above this event boundary. + * @param x - The x coordinate of the event. + * @param y - The y coordinate of the event. + */ + hitTest(x, y) { + EventsTicker.pauseUpdate = true; + const useMove = this._isPointerMoveEvent && this.enableGlobalMoveEvents; + const fn = useMove ? "hitTestMoveRecursive" : "hitTestRecursive"; + const invertedPath = this[fn]( + this.rootTarget, + this.rootTarget.eventMode, + tempHitLocation.set(x, y), + this.hitTestFn, + this.hitPruneFn + ); + return invertedPath && invertedPath[0]; + } + /** + * Propagate the passed event from from {@link EventBoundary.rootTarget this.rootTarget} to its + * target {@code e.target}. + * @param e - The event to propagate. + * @param type - The type of event to propagate. Defaults to `e.type`. + */ + propagate(e, type) { + if (!e.target) { + return; + } + const composedPath = e.composedPath(); + e.eventPhase = e.CAPTURING_PHASE; + for (let i = 0, j = composedPath.length - 1; i < j; i++) { + e.currentTarget = composedPath[i]; + this.notifyTarget(e, type); + if (e.propagationStopped || e.propagationImmediatelyStopped) + return; + } + e.eventPhase = e.AT_TARGET; + e.currentTarget = e.target; + this.notifyTarget(e, type); + if (e.propagationStopped || e.propagationImmediatelyStopped) + return; + e.eventPhase = e.BUBBLING_PHASE; + for (let i = composedPath.length - 2; i >= 0; i--) { + e.currentTarget = composedPath[i]; + this.notifyTarget(e, type); + if (e.propagationStopped || e.propagationImmediatelyStopped) + return; + } + } + /** + * Emits the event {@code e} to all interactive containers. The event is propagated in the bubbling phase always. + * + * This is used in the `globalpointermove` event. + * @param e - The emitted event. + * @param type - The listeners to notify. + * @param targets - The targets to notify. + */ + all(e, type, targets = this._allInteractiveElements) { + if (targets.length === 0) + return; + e.eventPhase = e.BUBBLING_PHASE; + const events = Array.isArray(type) ? type : [type]; + for (let i = targets.length - 1; i >= 0; i--) { + events.forEach((event) => { + e.currentTarget = targets[i]; + this.notifyTarget(e, event); + }); + } + } + /** + * Finds the propagation path from {@link EventBoundary.rootTarget rootTarget} to the passed + * {@code target}. The last element in the path is {@code target}. + * @param target - The target to find the propagation path to. + */ + propagationPath(target) { + const propagationPath = [target]; + for (let i = 0; i < PROPAGATION_LIMIT && (target !== this.rootTarget && target.parent); i++) { + if (!target.parent) { + throw new Error("Cannot find propagation path to disconnected target"); + } + propagationPath.push(target.parent); + target = target.parent; + } + propagationPath.reverse(); + return propagationPath; + } + hitTestMoveRecursive(currentTarget, eventMode, location, testFn, pruneFn, ignore = false) { + let shouldReturn = false; + if (this._interactivePrune(currentTarget)) + return null; + if (currentTarget.eventMode === "dynamic" || eventMode === "dynamic") { + EventsTicker.pauseUpdate = false; + } + if (currentTarget.interactiveChildren && currentTarget.children) { + const children = currentTarget.children; + for (let i = children.length - 1; i >= 0; i--) { + const child = children[i]; + const nestedHit = this.hitTestMoveRecursive( + child, + this._isInteractive(eventMode) ? eventMode : child.eventMode, + location, + testFn, + pruneFn, + ignore || pruneFn(currentTarget, location) + ); + if (nestedHit) { + if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) { + continue; + } + const isInteractive = currentTarget.isInteractive(); + if (nestedHit.length > 0 || isInteractive) { + if (isInteractive) + this._allInteractiveElements.push(currentTarget); + nestedHit.push(currentTarget); + } + if (this._hitElements.length === 0) + this._hitElements = nestedHit; + shouldReturn = true; + } + } + } + const isInteractiveMode = this._isInteractive(eventMode); + const isInteractiveTarget = currentTarget.isInteractive(); + if (isInteractiveTarget && isInteractiveTarget) + this._allInteractiveElements.push(currentTarget); + if (ignore || this._hitElements.length > 0) + return null; + if (shouldReturn) + return this._hitElements; + if (isInteractiveMode && (!pruneFn(currentTarget, location) && testFn(currentTarget, location))) { + return isInteractiveTarget ? [currentTarget] : []; + } + return null; + } + /** + * Recursive implementation for {@link EventBoundary.hitTest hitTest}. + * @param currentTarget - The Container that is to be hit tested. + * @param eventMode - The event mode for the `currentTarget` or one of its parents. + * @param location - The location that is being tested for overlap. + * @param testFn - Callback that determines whether the target passes hit testing. This callback + * can assume that `pruneFn` failed to prune the container. + * @param pruneFn - Callback that determiness whether the target and all of its children + * cannot pass the hit test. It is used as a preliminary optimization to prune entire subtrees + * of the scene graph. + * @returns An array holding the hit testing target and all its ancestors in order. The first element + * is the target itself and the last is {@link EventBoundary.rootTarget rootTarget}. This is the opposite + * order w.r.t. the propagation path. If no hit testing target is found, null is returned. + */ + hitTestRecursive(currentTarget, eventMode, location, testFn, pruneFn) { + if (this._interactivePrune(currentTarget) || pruneFn(currentTarget, location)) { + return null; + } + if (currentTarget.eventMode === "dynamic" || eventMode === "dynamic") { + EventsTicker.pauseUpdate = false; + } + if (currentTarget.interactiveChildren && currentTarget.children) { + const children = currentTarget.children; + const relativeLocation = location; + for (let i = children.length - 1; i >= 0; i--) { + const child = children[i]; + const nestedHit = this.hitTestRecursive( + child, + this._isInteractive(eventMode) ? eventMode : child.eventMode, + relativeLocation, + testFn, + pruneFn + ); + if (nestedHit) { + if (nestedHit.length > 0 && !nestedHit[nestedHit.length - 1].parent) { + continue; + } + const isInteractive = currentTarget.isInteractive(); + if (nestedHit.length > 0 || isInteractive) + nestedHit.push(currentTarget); + return nestedHit; + } + } + } + const isInteractiveMode = this._isInteractive(eventMode); + const isInteractiveTarget = currentTarget.isInteractive(); + if (isInteractiveMode && testFn(currentTarget, location)) { + return isInteractiveTarget ? [currentTarget] : []; + } + return null; + } + _isInteractive(int) { + return int === "static" || int === "dynamic"; + } + _interactivePrune(container) { + if (!container || !container.visible || !container.renderable || !container.includeInBuild || !container.measurable) { + return true; + } + if (container.eventMode === "none") { + return true; + } + if (container.eventMode === "passive" && !container.interactiveChildren) { + return true; + } + return false; + } + /** + * Checks whether the container or any of its children cannot pass the hit test at all. + * + * {@link EventBoundary}'s implementation uses the {@link Container.hitArea hitArea} + * and {@link Container._maskEffect} for pruning. + * @param container - The container to prune. + * @param location - The location to test for overlap. + */ + hitPruneFn(container, location) { + if (container.hitArea) { + container.worldTransform.applyInverse(location, tempLocalMapping); + if (!container.hitArea.contains(tempLocalMapping.x, tempLocalMapping.y)) { + return true; + } + } + if (container.effects && container.effects.length) { + for (let i = 0; i < container.effects.length; i++) { + const effect = container.effects[i]; + if (effect.containsPoint) { + const effectContainsPoint = effect.containsPoint(location, this.hitTestFn); + if (!effectContainsPoint) { + return true; + } + } + } + } + return false; + } + /** + * Checks whether the container passes hit testing for the given location. + * @param container - The container to test. + * @param location - The location to test for overlap. + * @returns - Whether `container` passes hit testing for `location`. + */ + hitTestFn(container, location) { + if (container.hitArea) { + return true; + } + if (container == null ? void 0 : container.containsPoint) { + container.worldTransform.applyInverse(location, tempLocalMapping); + return container.containsPoint(tempLocalMapping); + } + return false; + } + /** + * Notify all the listeners to the event's `currentTarget`. + * + * If the `currentTarget` contains the property `on`, then it is called here, + * simulating the behavior from version 6.x and prior. + * @param e - The event passed to the target. + * @param type - The type of event to notify. Defaults to `e.type`. + */ + notifyTarget(e, type) { + var _a, _b; + type = type != null ? type : e.type; + const handlerKey = `on${type}`; + (_b = (_a = e.currentTarget)[handlerKey]) == null ? void 0 : _b.call(_a, e); + const key = e.eventPhase === e.CAPTURING_PHASE || e.eventPhase === e.AT_TARGET ? `${type}capture` : type; + this._notifyListeners(e, key); + if (e.eventPhase === e.AT_TARGET) { + this._notifyListeners(e, type); + } + } + /** + * Maps the upstream `pointerdown` events to a downstream `pointerdown` event. + * + * `touchstart`, `rightdown`, `mousedown` events are also dispatched for specific pointer types. + * @param from - The upstream `pointerdown` event. + */ + mapPointerDown(from) { + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + const e = this.createPointerEvent(from); + this.dispatchEvent(e, "pointerdown"); + if (e.pointerType === "touch") { + this.dispatchEvent(e, "touchstart"); + } else if (e.pointerType === "mouse" || e.pointerType === "pen") { + const isRightButton = e.button === 2; + this.dispatchEvent(e, isRightButton ? "rightdown" : "mousedown"); + } + const trackingData = this.trackingData(from.pointerId); + trackingData.pressTargetsByButton[from.button] = e.composedPath(); + this.freeEvent(e); + } + /** + * Maps the upstream `pointermove` to downstream `pointerout`, `pointerover`, and `pointermove` events, in that order. + * + * The tracking data for the specific pointer has an updated `overTarget`. `mouseout`, `mouseover`, + * `mousemove`, and `touchmove` events are fired as well for specific pointer types. + * @param from - The upstream `pointermove` event. + */ + mapPointerMove(from) { + var _a, _b, _c; + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + this._allInteractiveElements.length = 0; + this._hitElements.length = 0; + this._isPointerMoveEvent = true; + const e = this.createPointerEvent(from); + this._isPointerMoveEvent = false; + const isMouse = e.pointerType === "mouse" || e.pointerType === "pen"; + const trackingData = this.trackingData(from.pointerId); + const outTarget = this.findMountedTarget(trackingData.overTargets); + if (((_a = trackingData.overTargets) == null ? void 0 : _a.length) > 0 && outTarget !== e.target) { + const outType = from.type === "mousemove" ? "mouseout" : "pointerout"; + const outEvent = this.createPointerEvent(from, outType, outTarget); + this.dispatchEvent(outEvent, "pointerout"); + if (isMouse) + this.dispatchEvent(outEvent, "mouseout"); + if (!e.composedPath().includes(outTarget)) { + const leaveEvent = this.createPointerEvent(from, "pointerleave", outTarget); + leaveEvent.eventPhase = leaveEvent.AT_TARGET; + while (leaveEvent.target && !e.composedPath().includes(leaveEvent.target)) { + leaveEvent.currentTarget = leaveEvent.target; + this.notifyTarget(leaveEvent); + if (isMouse) + this.notifyTarget(leaveEvent, "mouseleave"); + leaveEvent.target = leaveEvent.target.parent; + } + this.freeEvent(leaveEvent); + } + this.freeEvent(outEvent); + } + if (outTarget !== e.target) { + const overType = from.type === "mousemove" ? "mouseover" : "pointerover"; + const overEvent = this.clonePointerEvent(e, overType); + this.dispatchEvent(overEvent, "pointerover"); + if (isMouse) + this.dispatchEvent(overEvent, "mouseover"); + let overTargetAncestor = outTarget == null ? void 0 : outTarget.parent; + while (overTargetAncestor && overTargetAncestor !== this.rootTarget.parent) { + if (overTargetAncestor === e.target) + break; + overTargetAncestor = overTargetAncestor.parent; + } + const didPointerEnter = !overTargetAncestor || overTargetAncestor === this.rootTarget.parent; + if (didPointerEnter) { + const enterEvent = this.clonePointerEvent(e, "pointerenter"); + enterEvent.eventPhase = enterEvent.AT_TARGET; + while (enterEvent.target && enterEvent.target !== outTarget && enterEvent.target !== this.rootTarget.parent) { + enterEvent.currentTarget = enterEvent.target; + this.notifyTarget(enterEvent); + if (isMouse) + this.notifyTarget(enterEvent, "mouseenter"); + enterEvent.target = enterEvent.target.parent; + } + this.freeEvent(enterEvent); + } + this.freeEvent(overEvent); + } + const allMethods = []; + const allowGlobalPointerEvents = (_b = this.enableGlobalMoveEvents) != null ? _b : true; + this.moveOnAll ? allMethods.push("pointermove") : this.dispatchEvent(e, "pointermove"); + allowGlobalPointerEvents && allMethods.push("globalpointermove"); + if (e.pointerType === "touch") { + this.moveOnAll ? allMethods.splice(1, 0, "touchmove") : this.dispatchEvent(e, "touchmove"); + allowGlobalPointerEvents && allMethods.push("globaltouchmove"); + } + if (isMouse) { + this.moveOnAll ? allMethods.splice(1, 0, "mousemove") : this.dispatchEvent(e, "mousemove"); + allowGlobalPointerEvents && allMethods.push("globalmousemove"); + this.cursor = (_c = e.target) == null ? void 0 : _c.cursor; + } + if (allMethods.length > 0) { + this.all(e, allMethods); + } + this._allInteractiveElements.length = 0; + this._hitElements.length = 0; + trackingData.overTargets = e.composedPath(); + this.freeEvent(e); + } + /** + * Maps the upstream `pointerover` to downstream `pointerover` and `pointerenter` events, in that order. + * + * The tracking data for the specific pointer gets a new `overTarget`. + * @param from - The upstream `pointerover` event. + */ + mapPointerOver(from) { + var _a; + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + const trackingData = this.trackingData(from.pointerId); + const e = this.createPointerEvent(from); + const isMouse = e.pointerType === "mouse" || e.pointerType === "pen"; + this.dispatchEvent(e, "pointerover"); + if (isMouse) + this.dispatchEvent(e, "mouseover"); + if (e.pointerType === "mouse") + this.cursor = (_a = e.target) == null ? void 0 : _a.cursor; + const enterEvent = this.clonePointerEvent(e, "pointerenter"); + enterEvent.eventPhase = enterEvent.AT_TARGET; + while (enterEvent.target && enterEvent.target !== this.rootTarget.parent) { + enterEvent.currentTarget = enterEvent.target; + this.notifyTarget(enterEvent); + if (isMouse) + this.notifyTarget(enterEvent, "mouseenter"); + enterEvent.target = enterEvent.target.parent; + } + trackingData.overTargets = e.composedPath(); + this.freeEvent(e); + this.freeEvent(enterEvent); + } + /** + * Maps the upstream `pointerout` to downstream `pointerout`, `pointerleave` events, in that order. + * + * The tracking data for the specific pointer is cleared of a `overTarget`. + * @param from - The upstream `pointerout` event. + */ + mapPointerOut(from) { + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + const trackingData = this.trackingData(from.pointerId); + if (trackingData.overTargets) { + const isMouse = from.pointerType === "mouse" || from.pointerType === "pen"; + const outTarget = this.findMountedTarget(trackingData.overTargets); + const outEvent = this.createPointerEvent(from, "pointerout", outTarget); + this.dispatchEvent(outEvent); + if (isMouse) + this.dispatchEvent(outEvent, "mouseout"); + const leaveEvent = this.createPointerEvent(from, "pointerleave", outTarget); + leaveEvent.eventPhase = leaveEvent.AT_TARGET; + while (leaveEvent.target && leaveEvent.target !== this.rootTarget.parent) { + leaveEvent.currentTarget = leaveEvent.target; + this.notifyTarget(leaveEvent); + if (isMouse) + this.notifyTarget(leaveEvent, "mouseleave"); + leaveEvent.target = leaveEvent.target.parent; + } + trackingData.overTargets = null; + this.freeEvent(outEvent); + this.freeEvent(leaveEvent); + } + this.cursor = null; + } + /** + * Maps the upstream `pointerup` event to downstream `pointerup`, `pointerupoutside`, + * and `click`/`rightclick`/`pointertap` events, in that order. + * + * The `pointerupoutside` event bubbles from the original `pointerdown` target to the most specific + * ancestor of the `pointerdown` and `pointerup` targets, which is also the `click` event's target. `touchend`, + * `rightup`, `mouseup`, `touchendoutside`, `rightupoutside`, `mouseupoutside`, and `tap` are fired as well for + * specific pointer types. + * @param from - The upstream `pointerup` event. + */ + mapPointerUp(from) { + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + const now = performance.now(); + const e = this.createPointerEvent(from); + this.dispatchEvent(e, "pointerup"); + if (e.pointerType === "touch") { + this.dispatchEvent(e, "touchend"); + } else if (e.pointerType === "mouse" || e.pointerType === "pen") { + const isRightButton = e.button === 2; + this.dispatchEvent(e, isRightButton ? "rightup" : "mouseup"); + } + const trackingData = this.trackingData(from.pointerId); + const pressTarget = this.findMountedTarget(trackingData.pressTargetsByButton[from.button]); + let clickTarget = pressTarget; + if (pressTarget && !e.composedPath().includes(pressTarget)) { + let currentTarget = pressTarget; + while (currentTarget && !e.composedPath().includes(currentTarget)) { + e.currentTarget = currentTarget; + this.notifyTarget(e, "pointerupoutside"); + if (e.pointerType === "touch") { + this.notifyTarget(e, "touchendoutside"); + } else if (e.pointerType === "mouse" || e.pointerType === "pen") { + const isRightButton = e.button === 2; + this.notifyTarget(e, isRightButton ? "rightupoutside" : "mouseupoutside"); + } + currentTarget = currentTarget.parent; + } + delete trackingData.pressTargetsByButton[from.button]; + clickTarget = currentTarget; + } + if (clickTarget) { + const clickEvent = this.clonePointerEvent(e, "click"); + clickEvent.target = clickTarget; + clickEvent.path = null; + if (!trackingData.clicksByButton[from.button]) { + trackingData.clicksByButton[from.button] = { + clickCount: 0, + target: clickEvent.target, + timeStamp: now + }; + } + const clickHistory = trackingData.clicksByButton[from.button]; + if (clickHistory.target === clickEvent.target && now - clickHistory.timeStamp < 200) { + ++clickHistory.clickCount; + } else { + clickHistory.clickCount = 1; + } + clickHistory.target = clickEvent.target; + clickHistory.timeStamp = now; + clickEvent.detail = clickHistory.clickCount; + if (clickEvent.pointerType === "mouse") { + const isRightButton = clickEvent.button === 2; + this.dispatchEvent(clickEvent, isRightButton ? "rightclick" : "click"); + } else if (clickEvent.pointerType === "touch") { + this.dispatchEvent(clickEvent, "tap"); + } + this.dispatchEvent(clickEvent, "pointertap"); + this.freeEvent(clickEvent); + } + this.freeEvent(e); + } + /** + * Maps the upstream `pointerupoutside` event to a downstream `pointerupoutside` event, bubbling from the original + * `pointerdown` target to `rootTarget`. + * + * (The most specific ancestor of the `pointerdown` event and the `pointerup` event must the + * `{@link EventBoundary}'s root because the `pointerup` event occurred outside of the boundary.) + * + * `touchendoutside`, `mouseupoutside`, and `rightupoutside` events are fired as well for specific pointer + * types. The tracking data for the specific pointer is cleared of a `pressTarget`. + * @param from - The upstream `pointerupoutside` event. + */ + mapPointerUpOutside(from) { + if (!(from instanceof FederatedPointerEvent)) { + warn("EventBoundary cannot map a non-pointer event as a pointer event"); + return; + } + const trackingData = this.trackingData(from.pointerId); + const pressTarget = this.findMountedTarget(trackingData.pressTargetsByButton[from.button]); + const e = this.createPointerEvent(from); + if (pressTarget) { + let currentTarget = pressTarget; + while (currentTarget) { + e.currentTarget = currentTarget; + this.notifyTarget(e, "pointerupoutside"); + if (e.pointerType === "touch") { + this.notifyTarget(e, "touchendoutside"); + } else if (e.pointerType === "mouse" || e.pointerType === "pen") { + this.notifyTarget(e, e.button === 2 ? "rightupoutside" : "mouseupoutside"); + } + currentTarget = currentTarget.parent; + } + delete trackingData.pressTargetsByButton[from.button]; + } + this.freeEvent(e); + } + /** + * Maps the upstream `wheel` event to a downstream `wheel` event. + * @param from - The upstream `wheel` event. + */ + mapWheel(from) { + if (!(from instanceof FederatedWheelEvent)) { + warn("EventBoundary cannot map a non-wheel event as a wheel event"); + return; + } + const wheelEvent = this.createWheelEvent(from); + this.dispatchEvent(wheelEvent); + this.freeEvent(wheelEvent); + } + /** + * Finds the most specific event-target in the given propagation path that is still mounted in the scene graph. + * + * This is used to find the correct `pointerup` and `pointerout` target in the case that the original `pointerdown` + * or `pointerover` target was unmounted from the scene graph. + * @param propagationPath - The propagation path was valid in the past. + * @returns - The most specific event-target still mounted at the same location in the scene graph. + */ + findMountedTarget(propagationPath) { + if (!propagationPath) { + return null; + } + let currentTarget = propagationPath[0]; + for (let i = 1; i < propagationPath.length; i++) { + if (propagationPath[i].parent === currentTarget) { + currentTarget = propagationPath[i]; + } else { + break; + } + } + return currentTarget; + } + /** + * Creates an event whose {@code originalEvent} is {@code from}, with an optional `type` and `target` override. + * + * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}. + * @param from - The {@code originalEvent} for the returned event. + * @param [type=from.type] - The type of the returned event. + * @param target - The target of the returned event. + */ + createPointerEvent(from, type, target) { + var _a; + const event = this.allocateEvent(FederatedPointerEvent); + this.copyPointerData(from, event); + this.copyMouseData(from, event); + this.copyData(from, event); + event.nativeEvent = from.nativeEvent; + event.originalEvent = from; + event.target = (_a = target != null ? target : this.hitTest(event.global.x, event.global.y)) != null ? _a : this._hitElements[0]; + if (typeof type === "string") { + event.type = type; + } + return event; + } + /** + * Creates a wheel event whose {@code originalEvent} is {@code from}. + * + * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}. + * @param from - The upstream wheel event. + */ + createWheelEvent(from) { + const event = this.allocateEvent(FederatedWheelEvent); + this.copyWheelData(from, event); + this.copyMouseData(from, event); + this.copyData(from, event); + event.nativeEvent = from.nativeEvent; + event.originalEvent = from; + event.target = this.hitTest(event.global.x, event.global.y); + return event; + } + /** + * Clones the event {@code from}, with an optional {@code type} override. + * + * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}. + * @param from - The event to clone. + * @param [type=from.type] - The type of the returned event. + */ + clonePointerEvent(from, type) { + const event = this.allocateEvent(FederatedPointerEvent); + event.nativeEvent = from.nativeEvent; + event.originalEvent = from.originalEvent; + this.copyPointerData(from, event); + this.copyMouseData(from, event); + this.copyData(from, event); + event.target = from.target; + event.path = from.composedPath().slice(); + event.type = type != null ? type : event.type; + return event; + } + /** + * Copies wheel {@link FederatedWheelEvent} data from {@code from} into {@code to}. + * + * The following properties are copied: + * + deltaMode + * + deltaX + * + deltaY + * + deltaZ + * @param from - The event to copy data from. + * @param to - The event to copy data into. + */ + copyWheelData(from, to) { + to.deltaMode = from.deltaMode; + to.deltaX = from.deltaX; + to.deltaY = from.deltaY; + to.deltaZ = from.deltaZ; + } + /** + * Copies pointer {@link FederatedPointerEvent} data from {@code from} into {@code to}. + * + * The following properties are copied: + * + pointerId + * + width + * + height + * + isPrimary + * + pointerType + * + pressure + * + tangentialPressure + * + tiltX + * + tiltY + * @param from - The event to copy data from. + * @param to - The event to copy data into. + */ + copyPointerData(from, to) { + if (!(from instanceof FederatedPointerEvent && to instanceof FederatedPointerEvent)) + return; + to.pointerId = from.pointerId; + to.width = from.width; + to.height = from.height; + to.isPrimary = from.isPrimary; + to.pointerType = from.pointerType; + to.pressure = from.pressure; + to.tangentialPressure = from.tangentialPressure; + to.tiltX = from.tiltX; + to.tiltY = from.tiltY; + to.twist = from.twist; + } + /** + * Copies mouse {@link FederatedMouseEvent} data from {@code from} to {@code to}. + * + * The following properties are copied: + * + altKey + * + button + * + buttons + * + clientX + * + clientY + * + metaKey + * + movementX + * + movementY + * + pageX + * + pageY + * + x + * + y + * + screen + * + shiftKey + * + global + * @param from - The event to copy data from. + * @param to - The event to copy data into. + */ + copyMouseData(from, to) { + if (!(from instanceof FederatedMouseEvent && to instanceof FederatedMouseEvent)) + return; + to.altKey = from.altKey; + to.button = from.button; + to.buttons = from.buttons; + to.client.copyFrom(from.client); + to.ctrlKey = from.ctrlKey; + to.metaKey = from.metaKey; + to.movement.copyFrom(from.movement); + to.screen.copyFrom(from.screen); + to.shiftKey = from.shiftKey; + to.global.copyFrom(from.global); + } + /** + * Copies base {@link FederatedEvent} data from {@code from} into {@code to}. + * + * The following properties are copied: + * + isTrusted + * + srcElement + * + timeStamp + * + type + * @param from - The event to copy data from. + * @param to - The event to copy data into. + */ + copyData(from, to) { + to.isTrusted = from.isTrusted; + to.srcElement = from.srcElement; + to.timeStamp = performance.now(); + to.type = from.type; + to.detail = from.detail; + to.view = from.view; + to.which = from.which; + to.layer.copyFrom(from.layer); + to.page.copyFrom(from.page); + } + /** + * @param id - The pointer ID. + * @returns The tracking data stored for the given pointer. If no data exists, a blank + * state will be created. + */ + trackingData(id) { + if (!this.mappingState.trackingData[id]) { + this.mappingState.trackingData[id] = { + pressTargetsByButton: {}, + clicksByButton: {}, + overTarget: null + }; + } + return this.mappingState.trackingData[id]; + } + /** + * Allocate a specific type of event from {@link EventBoundary#eventPool this.eventPool}. + * + * This allocation is constructor-agnostic, as long as it only takes one argument - this event + * boundary. + * @param constructor - The event's constructor. + */ + allocateEvent(constructor) { + if (!this.eventPool.has(constructor)) { + this.eventPool.set(constructor, []); + } + const event = this.eventPool.get(constructor).pop() || new constructor(this); + event.eventPhase = event.NONE; + event.currentTarget = null; + event.path = null; + event.target = null; + return event; + } + /** + * Frees the event and puts it back into the event pool. + * + * It is illegal to reuse the event until it is allocated again, using `this.allocateEvent`. + * + * It is also advised that events not allocated from {@link EventBoundary#allocateEvent this.allocateEvent} + * not be freed. This is because of the possibility that the same event is freed twice, which can cause + * it to be allocated twice & result in overwriting. + * @param event - The event to be freed. + * @throws Error if the event is managed by another event boundary. + */ + freeEvent(event) { + if (event.manager !== this) + throw new Error("It is illegal to free an event not managed by this EventBoundary!"); + const constructor = event.constructor; + if (!this.eventPool.has(constructor)) { + this.eventPool.set(constructor, []); + } + this.eventPool.get(constructor).push(event); + } + /** + * Similar to {@link EventEmitter.emit}, except it stops if the `propagationImmediatelyStopped` flag + * is set on the event. + * @param e - The event to call each listener with. + * @param type - The event key. + */ + _notifyListeners(e, type) { + const listeners = e.currentTarget._events[type]; + if (!listeners) + return; + if (!e.currentTarget.isInteractive()) + return; + if ("fn" in listeners) { + if (listeners.once) + e.currentTarget.removeListener(type, listeners.fn, void 0, true); + listeners.fn.call(listeners.context, e); + } else { + for (let i = 0, j = listeners.length; i < j && !e.propagationImmediatelyStopped; i++) { + if (listeners[i].once) + e.currentTarget.removeListener(type, listeners[i].fn, void 0, true); + listeners[i].fn.call(listeners[i].context, e); + } + } + } + } + + "use strict"; + var __defProp$$ = Object.defineProperty; + var __getOwnPropSymbols$$ = Object.getOwnPropertySymbols; + var __hasOwnProp$$ = Object.prototype.hasOwnProperty; + var __propIsEnum$$ = Object.prototype.propertyIsEnumerable; + var __defNormalProp$$ = (obj, key, value) => key in obj ? __defProp$$(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$$ = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$$.call(b, prop)) + __defNormalProp$$(a, prop, b[prop]); + if (__getOwnPropSymbols$$) + for (var prop of __getOwnPropSymbols$$(b)) { + if (__propIsEnum$$.call(b, prop)) + __defNormalProp$$(a, prop, b[prop]); + } + return a; + }; + const MOUSE_POINTER_ID = 1; + const TOUCH_TO_POINTER = { + touchstart: "pointerdown", + touchend: "pointerup", + touchendoutside: "pointerupoutside", + touchmove: "pointermove", + touchcancel: "pointercancel" + }; + const _EventSystem = class _EventSystem { + /** + * @param {Renderer} renderer + */ + constructor(renderer) { + /** Does the device support touch events https://www.w3.org/TR/touch-events/ */ + this.supportsTouchEvents = "ontouchstart" in globalThis; + /** Does the device support pointer events https://www.w3.org/Submission/pointer-events/ */ + this.supportsPointerEvents = !!globalThis.PointerEvent; + /** + * The DOM element to which the root event listeners are bound. This is automatically set to + * the renderer's {@link Renderer#view view}. + */ + this.domElement = null; + /** The resolution used to convert between the DOM client space into world space. */ + this.resolution = 1; + this.renderer = renderer; + this.rootBoundary = new EventBoundary(null); + EventsTicker.init(this); + this.autoPreventDefault = true; + this._eventsAdded = false; + this._rootPointerEvent = new FederatedPointerEvent(null); + this._rootWheelEvent = new FederatedWheelEvent(null); + this.cursorStyles = { + default: "inherit", + pointer: "pointer" + }; + this.features = new Proxy(__spreadValues$$({}, _EventSystem.defaultEventFeatures), { + set: (target, key, value) => { + if (key === "globalMove") { + this.rootBoundary.enableGlobalMoveEvents = value; + } + target[key] = value; + return true; + } + }); + this._onPointerDown = this._onPointerDown.bind(this); + this._onPointerMove = this._onPointerMove.bind(this); + this._onPointerUp = this._onPointerUp.bind(this); + this._onPointerOverOut = this._onPointerOverOut.bind(this); + this.onWheel = this.onWheel.bind(this); + } + /** + * The default interaction mode for all display objects. + * @see Container.eventMode + * @type {EventMode} + * @readonly + * @since 7.2.0 + */ + static get defaultEventMode() { + return this._defaultEventMode; + } + /** + * Runner init called, view is available at this point. + * @ignore + */ + init(options) { + var _a, _b; + const { canvas, resolution } = this.renderer; + this.setTargetElement(canvas); + this.resolution = resolution; + _EventSystem._defaultEventMode = (_a = options.eventMode) != null ? _a : "passive"; + Object.assign(this.features, (_b = options.eventFeatures) != null ? _b : {}); + this.rootBoundary.enableGlobalMoveEvents = this.features.globalMove; + } + /** + * Handle changing resolution. + * @ignore + */ + resolutionChange(resolution) { + this.resolution = resolution; + } + /** Destroys all event listeners and detaches the renderer. */ + destroy() { + this.setTargetElement(null); + this.renderer = null; + this._currentCursor = null; + } + /** + * Sets the current cursor mode, handling any callbacks or CSS style changes. + * @param mode - cursor mode, a key from the cursorStyles dictionary + */ + setCursor(mode) { + mode = mode || "default"; + let applyStyles = true; + if (globalThis.OffscreenCanvas && this.domElement instanceof OffscreenCanvas) { + applyStyles = false; + } + if (this._currentCursor === mode) { + return; + } + this._currentCursor = mode; + const style = this.cursorStyles[mode]; + if (style) { + switch (typeof style) { + case "string": + if (applyStyles) { + this.domElement.style.cursor = style; + } + break; + case "function": + style(mode); + break; + case "object": + if (applyStyles) { + Object.assign(this.domElement.style, style); + } + break; + } + } else if (applyStyles && typeof mode === "string" && !Object.prototype.hasOwnProperty.call(this.cursorStyles, mode)) { + this.domElement.style.cursor = mode; + } + } + /** + * The global pointer event. + * Useful for getting the pointer position without listening to events. + * @since 7.2.0 + */ + get pointer() { + return this._rootPointerEvent; + } + /** + * Event handler for pointer down events on {@link EventSystem#domElement this.domElement}. + * @param nativeEvent - The native mouse/pointer/touch event. + */ + _onPointerDown(nativeEvent) { + if (!this.features.click) + return; + this.rootBoundary.rootTarget = this.renderer.lastObjectRendered; + const events = this._normalizeToPointerData(nativeEvent); + if (this.autoPreventDefault && events[0].isNormalized) { + const cancelable = nativeEvent.cancelable || !("cancelable" in nativeEvent); + if (cancelable) { + nativeEvent.preventDefault(); + } + } + for (let i = 0, j = events.length; i < j; i++) { + const nativeEvent2 = events[i]; + const federatedEvent = this._bootstrapEvent(this._rootPointerEvent, nativeEvent2); + this.rootBoundary.mapEvent(federatedEvent); + } + this.setCursor(this.rootBoundary.cursor); + } + /** + * Event handler for pointer move events on on {@link EventSystem#domElement this.domElement}. + * @param nativeEvent - The native mouse/pointer/touch events. + */ + _onPointerMove(nativeEvent) { + if (!this.features.move) + return; + this.rootBoundary.rootTarget = this.renderer.lastObjectRendered; + EventsTicker.pointerMoved(); + const normalizedEvents = this._normalizeToPointerData(nativeEvent); + for (let i = 0, j = normalizedEvents.length; i < j; i++) { + const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]); + this.rootBoundary.mapEvent(event); + } + this.setCursor(this.rootBoundary.cursor); + } + /** + * Event handler for pointer up events on {@link EventSystem#domElement this.domElement}. + * @param nativeEvent - The native mouse/pointer/touch event. + */ + _onPointerUp(nativeEvent) { + if (!this.features.click) + return; + this.rootBoundary.rootTarget = this.renderer.lastObjectRendered; + let target = nativeEvent.target; + if (nativeEvent.composedPath && nativeEvent.composedPath().length > 0) { + target = nativeEvent.composedPath()[0]; + } + const outside = target !== this.domElement ? "outside" : ""; + const normalizedEvents = this._normalizeToPointerData(nativeEvent); + for (let i = 0, j = normalizedEvents.length; i < j; i++) { + const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]); + event.type += outside; + this.rootBoundary.mapEvent(event); + } + this.setCursor(this.rootBoundary.cursor); + } + /** + * Event handler for pointer over & out events on {@link EventSystem#domElement this.domElement}. + * @param nativeEvent - The native mouse/pointer/touch event. + */ + _onPointerOverOut(nativeEvent) { + if (!this.features.click) + return; + this.rootBoundary.rootTarget = this.renderer.lastObjectRendered; + const normalizedEvents = this._normalizeToPointerData(nativeEvent); + for (let i = 0, j = normalizedEvents.length; i < j; i++) { + const event = this._bootstrapEvent(this._rootPointerEvent, normalizedEvents[i]); + this.rootBoundary.mapEvent(event); + } + this.setCursor(this.rootBoundary.cursor); + } + /** + * Passive handler for `wheel` events on {@link EventSystem.domElement this.domElement}. + * @param nativeEvent - The native wheel event. + */ + onWheel(nativeEvent) { + if (!this.features.wheel) + return; + const wheelEvent = this.normalizeWheelEvent(nativeEvent); + this.rootBoundary.rootTarget = this.renderer.lastObjectRendered; + this.rootBoundary.mapEvent(wheelEvent); + } + /** + * Sets the {@link EventSystem#domElement domElement} and binds event listeners. + * + * To deregister the current DOM element without setting a new one, pass {@code null}. + * @param element - The new DOM element. + */ + setTargetElement(element) { + this._removeEvents(); + this.domElement = element; + EventsTicker.domElement = element; + this._addEvents(); + } + /** Register event listeners on {@link Renderer#domElement this.domElement}. */ + _addEvents() { + if (this._eventsAdded || !this.domElement) { + return; + } + EventsTicker.addTickerListener(); + const style = this.domElement.style; + if (style) { + if (globalThis.navigator.msPointerEnabled) { + style.msContentZooming = "none"; + style.msTouchAction = "none"; + } else if (this.supportsPointerEvents) { + style.touchAction = "none"; + } + } + if (this.supportsPointerEvents) { + globalThis.document.addEventListener("pointermove", this._onPointerMove, true); + this.domElement.addEventListener("pointerdown", this._onPointerDown, true); + this.domElement.addEventListener("pointerleave", this._onPointerOverOut, true); + this.domElement.addEventListener("pointerover", this._onPointerOverOut, true); + globalThis.addEventListener("pointerup", this._onPointerUp, true); + } else { + globalThis.document.addEventListener("mousemove", this._onPointerMove, true); + this.domElement.addEventListener("mousedown", this._onPointerDown, true); + this.domElement.addEventListener("mouseout", this._onPointerOverOut, true); + this.domElement.addEventListener("mouseover", this._onPointerOverOut, true); + globalThis.addEventListener("mouseup", this._onPointerUp, true); + if (this.supportsTouchEvents) { + this.domElement.addEventListener("touchstart", this._onPointerDown, true); + this.domElement.addEventListener("touchend", this._onPointerUp, true); + this.domElement.addEventListener("touchmove", this._onPointerMove, true); + } + } + this.domElement.addEventListener("wheel", this.onWheel, { + passive: true, + capture: true + }); + this._eventsAdded = true; + } + /** Unregister event listeners on {@link EventSystem#domElement this.domElement}. */ + _removeEvents() { + if (!this._eventsAdded || !this.domElement) { + return; + } + EventsTicker.removeTickerListener(); + const style = this.domElement.style; + if (style) { + if (globalThis.navigator.msPointerEnabled) { + style.msContentZooming = ""; + style.msTouchAction = ""; + } else if (this.supportsPointerEvents) { + style.touchAction = ""; + } + } + if (this.supportsPointerEvents) { + globalThis.document.removeEventListener("pointermove", this._onPointerMove, true); + this.domElement.removeEventListener("pointerdown", this._onPointerDown, true); + this.domElement.removeEventListener("pointerleave", this._onPointerOverOut, true); + this.domElement.removeEventListener("pointerover", this._onPointerOverOut, true); + globalThis.removeEventListener("pointerup", this._onPointerUp, true); + } else { + globalThis.document.removeEventListener("mousemove", this._onPointerMove, true); + this.domElement.removeEventListener("mousedown", this._onPointerDown, true); + this.domElement.removeEventListener("mouseout", this._onPointerOverOut, true); + this.domElement.removeEventListener("mouseover", this._onPointerOverOut, true); + globalThis.removeEventListener("mouseup", this._onPointerUp, true); + if (this.supportsTouchEvents) { + this.domElement.removeEventListener("touchstart", this._onPointerDown, true); + this.domElement.removeEventListener("touchend", this._onPointerUp, true); + this.domElement.removeEventListener("touchmove", this._onPointerMove, true); + } + } + this.domElement.removeEventListener("wheel", this.onWheel, true); + this.domElement = null; + this._eventsAdded = false; + } + /** + * Maps x and y coords from a DOM object and maps them correctly to the PixiJS view. The + * resulting value is stored in the point. This takes into account the fact that the DOM + * element could be scaled and positioned anywhere on the screen. + * @param {PointData} point - the point that the result will be stored in + * @param {number} x - the x coord of the position to map + * @param {number} y - the y coord of the position to map + */ + mapPositionToPoint(point, x, y) { + const rect = this.domElement.isConnected ? this.domElement.getBoundingClientRect() : { + x: 0, + y: 0, + width: this.domElement.width, + height: this.domElement.height, + left: 0, + top: 0 + }; + const resolutionMultiplier = 1 / this.resolution; + point.x = (x - rect.left) * (this.domElement.width / rect.width) * resolutionMultiplier; + point.y = (y - rect.top) * (this.domElement.height / rect.height) * resolutionMultiplier; + } + /** + * Ensures that the original event object contains all data that a regular pointer event would have + * @param event - The original event data from a touch or mouse event + * @returns An array containing a single normalized pointer event, in the case of a pointer + * or mouse event, or a multiple normalized pointer events if there are multiple changed touches + */ + _normalizeToPointerData(event) { + const normalizedEvents = []; + if (this.supportsTouchEvents && event instanceof TouchEvent) { + for (let i = 0, li = event.changedTouches.length; i < li; i++) { + const touch = event.changedTouches[i]; + if (typeof touch.button === "undefined") + touch.button = 0; + if (typeof touch.buttons === "undefined") + touch.buttons = 1; + if (typeof touch.isPrimary === "undefined") { + touch.isPrimary = event.touches.length === 1 && event.type === "touchstart"; + } + if (typeof touch.width === "undefined") + touch.width = touch.radiusX || 1; + if (typeof touch.height === "undefined") + touch.height = touch.radiusY || 1; + if (typeof touch.tiltX === "undefined") + touch.tiltX = 0; + if (typeof touch.tiltY === "undefined") + touch.tiltY = 0; + if (typeof touch.pointerType === "undefined") + touch.pointerType = "touch"; + if (typeof touch.pointerId === "undefined") + touch.pointerId = touch.identifier || 0; + if (typeof touch.pressure === "undefined") + touch.pressure = touch.force || 0.5; + if (typeof touch.twist === "undefined") + touch.twist = 0; + if (typeof touch.tangentialPressure === "undefined") + touch.tangentialPressure = 0; + if (typeof touch.layerX === "undefined") + touch.layerX = touch.offsetX = touch.clientX; + if (typeof touch.layerY === "undefined") + touch.layerY = touch.offsetY = touch.clientY; + touch.isNormalized = true; + touch.type = event.type; + normalizedEvents.push(touch); + } + } else if (!globalThis.MouseEvent || event instanceof MouseEvent && (!this.supportsPointerEvents || !(event instanceof globalThis.PointerEvent))) { + const tempEvent = event; + if (typeof tempEvent.isPrimary === "undefined") + tempEvent.isPrimary = true; + if (typeof tempEvent.width === "undefined") + tempEvent.width = 1; + if (typeof tempEvent.height === "undefined") + tempEvent.height = 1; + if (typeof tempEvent.tiltX === "undefined") + tempEvent.tiltX = 0; + if (typeof tempEvent.tiltY === "undefined") + tempEvent.tiltY = 0; + if (typeof tempEvent.pointerType === "undefined") + tempEvent.pointerType = "mouse"; + if (typeof tempEvent.pointerId === "undefined") + tempEvent.pointerId = MOUSE_POINTER_ID; + if (typeof tempEvent.pressure === "undefined") + tempEvent.pressure = 0.5; + if (typeof tempEvent.twist === "undefined") + tempEvent.twist = 0; + if (typeof tempEvent.tangentialPressure === "undefined") + tempEvent.tangentialPressure = 0; + tempEvent.isNormalized = true; + normalizedEvents.push(tempEvent); + } else { + normalizedEvents.push(event); + } + return normalizedEvents; + } + /** + * Normalizes the native {@link https://w3c.github.io/uievents/#interface-wheelevent WheelEvent}. + * + * The returned {@link FederatedWheelEvent} is a shared instance. It will not persist across + * multiple native wheel events. + * @param nativeEvent - The native wheel event that occurred on the canvas. + * @returns A federated wheel event. + */ + normalizeWheelEvent(nativeEvent) { + const event = this._rootWheelEvent; + this._transferMouseData(event, nativeEvent); + event.deltaX = nativeEvent.deltaX; + event.deltaY = nativeEvent.deltaY; + event.deltaZ = nativeEvent.deltaZ; + event.deltaMode = nativeEvent.deltaMode; + this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY); + event.global.copyFrom(event.screen); + event.offset.copyFrom(event.screen); + event.nativeEvent = nativeEvent; + event.type = nativeEvent.type; + return event; + } + /** + * Normalizes the `nativeEvent` into a federateed {@link FederatedPointerEvent}. + * @param event + * @param nativeEvent + */ + _bootstrapEvent(event, nativeEvent) { + event.originalEvent = null; + event.nativeEvent = nativeEvent; + event.pointerId = nativeEvent.pointerId; + event.width = nativeEvent.width; + event.height = nativeEvent.height; + event.isPrimary = nativeEvent.isPrimary; + event.pointerType = nativeEvent.pointerType; + event.pressure = nativeEvent.pressure; + event.tangentialPressure = nativeEvent.tangentialPressure; + event.tiltX = nativeEvent.tiltX; + event.tiltY = nativeEvent.tiltY; + event.twist = nativeEvent.twist; + this._transferMouseData(event, nativeEvent); + this.mapPositionToPoint(event.screen, nativeEvent.clientX, nativeEvent.clientY); + event.global.copyFrom(event.screen); + event.offset.copyFrom(event.screen); + event.isTrusted = nativeEvent.isTrusted; + if (event.type === "pointerleave") { + event.type = "pointerout"; + } + if (event.type.startsWith("mouse")) { + event.type = event.type.replace("mouse", "pointer"); + } + if (event.type.startsWith("touch")) { + event.type = TOUCH_TO_POINTER[event.type] || event.type; + } + return event; + } + /** + * Transfers base & mouse event data from the {@code nativeEvent} to the federated event. + * @param event + * @param nativeEvent + */ + _transferMouseData(event, nativeEvent) { + event.isTrusted = nativeEvent.isTrusted; + event.srcElement = nativeEvent.srcElement; + event.timeStamp = performance.now(); + event.type = nativeEvent.type; + event.altKey = nativeEvent.altKey; + event.button = nativeEvent.button; + event.buttons = nativeEvent.buttons; + event.client.x = nativeEvent.clientX; + event.client.y = nativeEvent.clientY; + event.ctrlKey = nativeEvent.ctrlKey; + event.metaKey = nativeEvent.metaKey; + event.movement.x = nativeEvent.movementX; + event.movement.y = nativeEvent.movementY; + event.page.x = nativeEvent.pageX; + event.page.y = nativeEvent.pageY; + event.relatedTarget = null; + event.shiftKey = nativeEvent.shiftKey; + } + }; + /** @ignore */ + _EventSystem.extension = { + name: "events", + type: [ + ExtensionType.WebGLSystem, + ExtensionType.CanvasSystem, + ExtensionType.WebGPUSystem + ], + priority: -1 + }; + /** + * The event features that are enabled by the EventSystem + * (included in the **pixi.js** and **pixi.js-legacy** bundle), otherwise it will be ignored. + * @since 7.2.0 + */ + _EventSystem.defaultEventFeatures = { + /** Enables pointer events associated with pointer movement. */ + move: true, + /** Enables global pointer move events. */ + globalMove: true, + /** Enables pointer events associated with clicking. */ + click: true, + /** Enables wheel events. */ + wheel: true + }; + let EventSystem = _EventSystem; + + "use strict"; + const FederatedContainer = { + /** + * Property-based event handler for the `click` event. + * @memberof scene.Container# + * @default null + * @example + * this.onclick = (event) => { + * //some function here that happens on click + * } + */ + onclick: null, + /** + * Property-based event handler for the `mousedown` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmousedown = (event) => { + * //some function here that happens on mousedown + * } + */ + onmousedown: null, + /** + * Property-based event handler for the `mouseenter` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseenter = (event) => { + * //some function here that happens on mouseenter + * } + */ + onmouseenter: null, + /** + * Property-based event handler for the `mouseleave` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseleave = (event) => { + * //some function here that happens on mouseleave + * } + */ + onmouseleave: null, + /** + * Property-based event handler for the `mousemove` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmousemove = (event) => { + * //some function here that happens on mousemove + * } + */ + onmousemove: null, + /** + * Property-based event handler for the `globalmousemove` event. + * @memberof scene.Container# + * @default null + * @example + * this.onglobalmousemove = (event) => { + * //some function here that happens on globalmousemove + * } + */ + onglobalmousemove: null, + /** + * Property-based event handler for the `mouseout` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseout = (event) => { + * //some function here that happens on mouseout + * } + */ + onmouseout: null, + /** + * Property-based event handler for the `mouseover` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseover = (event) => { + * //some function here that happens on mouseover + * } + */ + onmouseover: null, + /** + * Property-based event handler for the `mouseup` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseup = (event) => { + * //some function here that happens on mouseup + * } + */ + onmouseup: null, + /** + * Property-based event handler for the `mouseupoutside` event. + * @memberof scene.Container# + * @default null + * @example + * this.onmouseupoutside = (event) => { + * //some function here that happens on mouseupoutside + * } + */ + onmouseupoutside: null, + /** + * Property-based event handler for the `pointercancel` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointercancel = (event) => { + * //some function here that happens on pointercancel + * } + */ + onpointercancel: null, + /** + * Property-based event handler for the `pointerdown` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerdown = (event) => { + * //some function here that happens on pointerdown + * } + */ + onpointerdown: null, + /** + * Property-based event handler for the `pointerenter` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerenter = (event) => { + * //some function here that happens on pointerenter + * } + */ + onpointerenter: null, + /** + * Property-based event handler for the `pointerleave` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerleave = (event) => { + * //some function here that happens on pointerleave + * } + */ + onpointerleave: null, + /** + * Property-based event handler for the `pointermove` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointermove = (event) => { + * //some function here that happens on pointermove + * } + */ + onpointermove: null, + /** + * Property-based event handler for the `globalpointermove` event. + * @memberof scene.Container# + * @default null + * @example + * this.onglobalpointermove = (event) => { + * //some function here that happens on globalpointermove + * } + */ + onglobalpointermove: null, + /** + * Property-based event handler for the `pointerout` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerout = (event) => { + * //some function here that happens on pointerout + * } + */ + onpointerout: null, + /** + * Property-based event handler for the `pointerover` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerover = (event) => { + * //some function here that happens on pointerover + * } + */ + onpointerover: null, + /** + * Property-based event handler for the `pointertap` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointertap = (event) => { + * //some function here that happens on pointertap + * } + */ + onpointertap: null, + /** + * Property-based event handler for the `pointerup` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerup = (event) => { + * //some function here that happens on pointerup + * } + */ + onpointerup: null, + /** + * Property-based event handler for the `pointerupoutside` event. + * @memberof scene.Container# + * @default null + * @example + * this.onpointerupoutside = (event) => { + * //some function here that happens on pointerupoutside + * } + */ + onpointerupoutside: null, + /** + * Property-based event handler for the `rightclick` event. + * @memberof scene.Container# + * @default null + * @example + * this.onrightclick = (event) => { + * //some function here that happens on rightclick + * } + */ + onrightclick: null, + /** + * Property-based event handler for the `rightdown` event. + * @memberof scene.Container# + * @default null + * @example + * this.onrightdown = (event) => { + * //some function here that happens on rightdown + * } + */ + onrightdown: null, + /** + * Property-based event handler for the `rightup` event. + * @memberof scene.Container# + * @default null + * @example + * this.onrightup = (event) => { + * //some function here that happens on rightup + * } + */ + onrightup: null, + /** + * Property-based event handler for the `rightupoutside` event. + * @memberof scene.Container# + * @default null + * @example + * this.onrightupoutside = (event) => { + * //some function here that happens on rightupoutside + * } + */ + onrightupoutside: null, + /** + * Property-based event handler for the `tap` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontap = (event) => { + * //some function here that happens on tap + * } + */ + ontap: null, + /** + * Property-based event handler for the `touchcancel` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontouchcancel = (event) => { + * //some function here that happens on touchcancel + * } + */ + ontouchcancel: null, + /** + * Property-based event handler for the `touchend` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontouchend = (event) => { + * //some function here that happens on touchend + * } + */ + ontouchend: null, + /** + * Property-based event handler for the `touchendoutside` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontouchendoutside = (event) => { + * //some function here that happens on touchendoutside + * } + */ + ontouchendoutside: null, + /** + * Property-based event handler for the `touchmove` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontouchmove = (event) => { + * //some function here that happens on touchmove + * } + */ + ontouchmove: null, + /** + * Property-based event handler for the `globaltouchmove` event. + * @memberof scene.Container# + * @default null + * @example + * this.onglobaltouchmove = (event) => { + * //some function here that happens on globaltouchmove + * } + */ + onglobaltouchmove: null, + /** + * Property-based event handler for the `touchstart` event. + * @memberof scene.Container# + * @default null + * @example + * this.ontouchstart = (event) => { + * //some function here that happens on touchstart + * } + */ + ontouchstart: null, + /** + * Property-based event handler for the `wheel` event. + * @memberof scene.Container# + * @default null + * @example + * this.onwheel = (event) => { + * //some function here that happens on wheel + * } + */ + onwheel: null, + /** + * Enable interaction events for the Container. Touch, pointer and mouse + * @memberof scene.Container# + */ + get interactive() { + return this.eventMode === "dynamic" || this.eventMode === "static"; + }, + set interactive(value) { + this.eventMode = value ? "static" : "passive"; + }, + /** + * @ignore + */ + _internalEventMode: void 0, + /** + * Enable interaction events for the Container. Touch, pointer and mouse. + * There are 5 types of interaction settings: + * - `'none'`: Ignores all interaction events, even on its children. + * - `'passive'`: **(default)** Does not emit events and ignores all hit testing on itself and non-interactive children. + * Interactive children will still emit events. + * - `'auto'`: Does not emit events but is hit tested if parent is interactive. Same as `interactive = false` in v7 + * - `'static'`: Emit events and is hit tested. Same as `interaction = true` in v7 + * - `'dynamic'`: Emits events and is hit tested but will also receive mock interaction events fired from a ticker to + * allow for interaction when the mouse isn't moving + * @example + * import { Sprite } from 'pixi.js'; + * + * const sprite = new Sprite(texture); + * sprite.eventMode = 'static'; + * sprite.on('tap', (event) => { + * // Handle event + * }); + * @memberof scene.Container# + * @since 7.2.0 + */ + get eventMode() { + var _a; + return (_a = this._internalEventMode) != null ? _a : EventSystem.defaultEventMode; + }, + set eventMode(value) { + this._internalEventMode = value; + }, + /** + * Determines if the container is interactive or not + * @returns {boolean} Whether the container is interactive or not + * @memberof scene.Container# + * @since 7.2.0 + * @example + * import { Sprite } from 'pixi.js'; + * + * const sprite = new Sprite(texture); + * sprite.eventMode = 'static'; + * sprite.isInteractive(); // true + * + * sprite.eventMode = 'dynamic'; + * sprite.isInteractive(); // true + * + * sprite.eventMode = 'none'; + * sprite.isInteractive(); // false + * + * sprite.eventMode = 'passive'; + * sprite.isInteractive(); // false + * + * sprite.eventMode = 'auto'; + * sprite.isInteractive(); // false + */ + isInteractive() { + return this.eventMode === "static" || this.eventMode === "dynamic"; + }, + /** + * Determines if the children to the container can be clicked/touched + * Setting this to false allows PixiJS to bypass a recursive `hitTest` function + * @memberof scene.Container# + */ + interactiveChildren: true, + /** + * Interaction shape. Children will be hit first, then this shape will be checked. + * Setting this will cause this shape to be checked in hit tests rather than the container's bounds. + * @example + * import { Rectangle, Sprite } from 'pixi.js'; + * + * const sprite = new Sprite(texture); + * sprite.interactive = true; + * sprite.hitArea = new Rectangle(0, 0, 100, 100); + * @member {IHitArea} + * @memberof scene.Container# + */ + hitArea: null, + /** + * Unlike `on` or `addListener` which are methods from EventEmitter, `addEventListener` + * seeks to be compatible with the DOM's `addEventListener` with support for options. + * @memberof scene.Container + * @param type - The type of event to listen to. + * @param listener - The listener callback or object. + * @param options - Listener options, used for capture phase. + * @example + * // Tell the user whether they did a single, double, triple, or nth click. + * button.addEventListener('click', { + * handleEvent(e): { + * let prefix; + * + * switch (e.detail) { + * case 1: prefix = 'single'; break; + * case 2: prefix = 'double'; break; + * case 3: prefix = 'triple'; break; + * default: prefix = e.detail + 'th'; break; + * } + * + * console.log('That was a ' + prefix + 'click'); + * } + * }); + * + * // But skip the first click! + * button.parent.addEventListener('click', function blockClickOnce(e) { + * e.stopImmediatePropagation(); + * button.parent.removeEventListener('click', blockClickOnce, true); + * }, { + * capture: true, + * }); + */ + addEventListener(type, listener, options) { + const capture = typeof options === "boolean" && options || typeof options === "object" && options.capture; + const signal = typeof options === "object" ? options.signal : void 0; + const once = typeof options === "object" ? options.once === true : false; + const context = typeof listener === "function" ? void 0 : listener; + type = capture ? `${type}capture` : type; + const listenerFn = typeof listener === "function" ? listener : listener.handleEvent; + const emitter = this; + if (signal) { + signal.addEventListener("abort", () => { + emitter.off(type, listenerFn, context); + }); + } + if (once) { + emitter.once(type, listenerFn, context); + } else { + emitter.on(type, listenerFn, context); + } + }, + /** + * Unlike `off` or `removeListener` which are methods from EventEmitter, `removeEventListener` + * seeks to be compatible with the DOM's `removeEventListener` with support for options. + * @memberof scene.Container + * @param type - The type of event the listener is bound to. + * @param listener - The listener callback or object. + * @param options - The original listener options. This is required to deregister a capture phase listener. + */ + removeEventListener(type, listener, options) { + const capture = typeof options === "boolean" && options || typeof options === "object" && options.capture; + const context = typeof listener === "function" ? void 0 : listener; + type = capture ? `${type}capture` : type; + listener = typeof listener === "function" ? listener : listener.handleEvent; + this.off(type, listener, context); + }, + /** + * Dispatch the event on this {@link Container} using the event's {@link EventBoundary}. + * + * The target of the event is set to `this` and the `defaultPrevented` flag is cleared before dispatch. + * @memberof scene.Container + * @param e - The event to dispatch. + * @returns Whether the {@link FederatedEvent.preventDefault preventDefault}() method was not invoked. + * @example + * // Reuse a click event! + * button.dispatchEvent(clickEvent); + */ + dispatchEvent(e) { + if (!(e instanceof FederatedEvent)) { + throw new Error("Container cannot propagate events outside of the Federated Events API"); + } + e.defaultPrevented = false; + e.path = null; + e.target = this; + e.manager.dispatchEvent(e); + return !e.defaultPrevented; + } + }; + + "use strict"; + extensions.add(EventSystem); + Container.mixin(FederatedContainer); + + "use strict"; + var LoaderParserPriority = /* @__PURE__ */ ((LoaderParserPriority2) => { + LoaderParserPriority2[LoaderParserPriority2["Low"] = 0] = "Low"; + LoaderParserPriority2[LoaderParserPriority2["Normal"] = 1] = "Normal"; + LoaderParserPriority2[LoaderParserPriority2["High"] = 2] = "High"; + return LoaderParserPriority2; + })(LoaderParserPriority || {}); + + "use strict"; + const BrowserAdapter = { + createCanvas: (width, height) => { + const canvas = document.createElement("canvas"); + canvas.width = width; + canvas.height = height; + return canvas; + }, + getCanvasRenderingContext2D: () => CanvasRenderingContext2D, + getWebGLRenderingContext: () => WebGLRenderingContext, + getNavigator: () => navigator, + getBaseUrl: () => { + var _a; + return (_a = document.baseURI) != null ? _a : window.location.href; + }, + getFontFaceSet: () => document.fonts, + fetch: (url, options) => fetch(url, options), + parseXML: (xml) => { + const parser = new DOMParser(); + return parser.parseFromString(xml, "text/xml"); + } + }; + + "use strict"; + let currentAdapter = BrowserAdapter; + const DOMAdapter = { + /** + * Returns the current adapter. + * @returns {environment.Adapter} The current adapter. + */ + get() { + return currentAdapter; + }, + /** + * Sets the current adapter. + * @param adapter - The new adapter. + */ + set(adapter) { + currentAdapter = adapter; + } + }; + + "use strict"; + function assertPath(path2) { + if (typeof path2 !== "string") { + throw new TypeError(`Path must be a string. Received ${JSON.stringify(path2)}`); + } + } + function removeUrlParams(url) { + const re = url.split("?")[0]; + return re.split("#")[0]; + } + function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + function replaceAll(str, find, replace) { + return str.replace(new RegExp(escapeRegExp(find), "g"), replace); + } + function normalizeStringPosix(path2, allowAboveRoot) { + let res = ""; + let lastSegmentLength = 0; + let lastSlash = -1; + let dots = 0; + let code = -1; + for (let i = 0; i <= path2.length; ++i) { + if (i < path2.length) { + code = path2.charCodeAt(i); + } else if (code === 47) { + break; + } else { + code = 47; + } + if (code === 47) { + if (lastSlash === i - 1 || dots === 1) { + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 || res.charCodeAt(res.length - 2) !== 46) { + if (res.length > 2) { + const lastSlashIndex = res.lastIndexOf("/"); + if (lastSlashIndex !== res.length - 1) { + if (lastSlashIndex === -1) { + res = ""; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf("/"); + } + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ""; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) { + res += "/.."; + } else { + res = ".."; + } + lastSegmentLength = 2; + } + } else { + if (res.length > 0) { + res += `/${path2.slice(lastSlash + 1, i)}`; + } else { + res = path2.slice(lastSlash + 1, i); + } + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; + } + const path = { + /** + * Converts a path to posix format. + * @param path - The path to convert to posix + */ + toPosix(path2) { + return replaceAll(path2, "\\", "/"); + }, + /** + * Checks if the path is a URL e.g. http://, https:// + * @param path - The path to check + */ + isUrl(path2) { + return /^https?:/.test(this.toPosix(path2)); + }, + /** + * Checks if the path is a data URL + * @param path - The path to check + */ + isDataUrl(path2) { + return /^data:([a-z]+\/[a-z0-9-+.]+(;[a-z0-9-.!#$%*+.{}|~`]+=[a-z0-9-.!#$%*+.{}()_|~`]+)*)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s<>]*?)$/i.test(path2); + }, + /** + * Checks if the path is a blob URL + * @param path - The path to check + */ + isBlobUrl(path2) { + return path2.startsWith("blob:"); + }, + /** + * Checks if the path has a protocol e.g. http://, https://, file:///, data:, blob:, C:/ + * This will return true for windows file paths + * @param path - The path to check + */ + hasProtocol(path2) { + return /^[^/:]+:/.test(this.toPosix(path2)); + }, + /** + * Returns the protocol of the path e.g. http://, https://, file:///, data:, blob:, C:/ + * @param path - The path to get the protocol from + */ + getProtocol(path2) { + assertPath(path2); + path2 = this.toPosix(path2); + const matchFile = /^file:\/\/\//.exec(path2); + if (matchFile) { + return matchFile[0]; + } + const matchProtocol = /^[^/:]+:\/{0,2}/.exec(path2); + if (matchProtocol) { + return matchProtocol[0]; + } + return ""; + }, + /** + * Converts URL to an absolute path. + * When loading from a Web Worker, we must use absolute paths. + * If the URL is already absolute we return it as is + * If it's not, we convert it + * @param url - The URL to test + * @param customBaseUrl - The base URL to use + * @param customRootUrl - The root URL to use + */ + toAbsolute(url, customBaseUrl, customRootUrl) { + assertPath(url); + if (this.isDataUrl(url) || this.isBlobUrl(url)) + return url; + const baseUrl = removeUrlParams(this.toPosix(customBaseUrl != null ? customBaseUrl : DOMAdapter.get().getBaseUrl())); + const rootUrl = removeUrlParams(this.toPosix(customRootUrl != null ? customRootUrl : this.rootname(baseUrl))); + url = this.toPosix(url); + if (url.startsWith("/")) { + return path.join(rootUrl, url.slice(1)); + } + const absolutePath = this.isAbsolute(url) ? url : this.join(baseUrl, url); + return absolutePath; + }, + /** + * Normalizes the given path, resolving '..' and '.' segments + * @param path - The path to normalize + */ + normalize(path2) { + assertPath(path2); + if (path2.length === 0) + return "."; + if (this.isDataUrl(path2) || this.isBlobUrl(path2)) + return path2; + path2 = this.toPosix(path2); + let protocol = ""; + const isAbsolute = path2.startsWith("/"); + if (this.hasProtocol(path2)) { + protocol = this.rootname(path2); + path2 = path2.slice(protocol.length); + } + const trailingSeparator = path2.endsWith("/"); + path2 = normalizeStringPosix(path2, false); + if (path2.length > 0 && trailingSeparator) + path2 += "/"; + if (isAbsolute) + return `/${path2}`; + return protocol + path2; + }, + /** + * Determines if path is an absolute path. + * Absolute paths can be urls, data urls, or paths on disk + * @param path - The path to test + */ + isAbsolute(path2) { + assertPath(path2); + path2 = this.toPosix(path2); + if (this.hasProtocol(path2)) + return true; + return path2.startsWith("/"); + }, + /** + * Joins all given path segments together using the platform-specific separator as a delimiter, + * then normalizes the resulting path + * @param segments - The segments of the path to join + */ + join(...segments) { + var _a; + if (segments.length === 0) { + return "."; + } + let joined; + for (let i = 0; i < segments.length; ++i) { + const arg = segments[i]; + assertPath(arg); + if (arg.length > 0) { + if (joined === void 0) + joined = arg; + else { + const prevArg = (_a = segments[i - 1]) != null ? _a : ""; + if (this.joinExtensions.includes(this.extname(prevArg).toLowerCase())) { + joined += `/../${arg}`; + } else { + joined += `/${arg}`; + } + } + } + } + if (joined === void 0) { + return "."; + } + return this.normalize(joined); + }, + /** + * Returns the directory name of a path + * @param path - The path to parse + */ + dirname(path2) { + assertPath(path2); + if (path2.length === 0) + return "."; + path2 = this.toPosix(path2); + let code = path2.charCodeAt(0); + const hasRoot = code === 47; + let end = -1; + let matchedSlash = true; + const proto = this.getProtocol(path2); + const origpath = path2; + path2 = path2.slice(proto.length); + for (let i = path2.length - 1; i >= 1; --i) { + code = path2.charCodeAt(i); + if (code === 47) { + if (!matchedSlash) { + end = i; + break; + } + } else { + matchedSlash = false; + } + } + if (end === -1) + return hasRoot ? "/" : this.isUrl(origpath) ? proto + path2 : proto; + if (hasRoot && end === 1) + return "//"; + return proto + path2.slice(0, end); + }, + /** + * Returns the root of the path e.g. /, C:/, file:///, http://domain.com/ + * @param path - The path to parse + */ + rootname(path2) { + assertPath(path2); + path2 = this.toPosix(path2); + let root = ""; + if (path2.startsWith("/")) + root = "/"; + else { + root = this.getProtocol(path2); + } + if (this.isUrl(path2)) { + const index = path2.indexOf("/", root.length); + if (index !== -1) { + root = path2.slice(0, index); + } else + root = path2; + if (!root.endsWith("/")) + root += "/"; + } + return root; + }, + /** + * Returns the last portion of a path + * @param path - The path to test + * @param ext - Optional extension to remove + */ + basename(path2, ext) { + assertPath(path2); + if (ext) + assertPath(ext); + path2 = removeUrlParams(this.toPosix(path2)); + let start = 0; + let end = -1; + let matchedSlash = true; + let i; + if (ext !== void 0 && ext.length > 0 && ext.length <= path2.length) { + if (ext.length === path2.length && ext === path2) + return ""; + let extIdx = ext.length - 1; + let firstNonSlashEnd = -1; + for (i = path2.length - 1; i >= 0; --i) { + const code = path2.charCodeAt(i); + if (code === 47) { + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + end = i; + } + } else { + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + if (start === end) + end = firstNonSlashEnd; + else if (end === -1) + end = path2.length; + return path2.slice(start, end); + } + for (i = path2.length - 1; i >= 0; --i) { + if (path2.charCodeAt(i) === 47) { + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + matchedSlash = false; + end = i + 1; + } + } + if (end === -1) + return ""; + return path2.slice(start, end); + }, + /** + * Returns the extension of the path, from the last occurrence of the . (period) character to end of string in the last + * portion of the path. If there is no . in the last portion of the path, or if there are no . characters other than + * the first character of the basename of path, an empty string is returned. + * @param path - The path to parse + */ + extname(path2) { + assertPath(path2); + path2 = removeUrlParams(this.toPosix(path2)); + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + let preDotState = 0; + for (let i = path2.length - 1; i >= 0; --i) { + const code = path2.charCodeAt(i); + if (code === 47) { + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + matchedSlash = false; + end = i + 1; + } + if (code === 46) { + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + preDotState = -1; + } + } + if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + return ""; + } + return path2.slice(startDot, end); + }, + /** + * Parses a path into an object containing the 'root', `dir`, `base`, `ext`, and `name` properties. + * @param path - The path to parse + */ + parse(path2) { + assertPath(path2); + const ret = { root: "", dir: "", base: "", ext: "", name: "" }; + if (path2.length === 0) + return ret; + path2 = removeUrlParams(this.toPosix(path2)); + let code = path2.charCodeAt(0); + const isAbsolute = this.isAbsolute(path2); + let start; + const protocol = ""; + ret.root = this.rootname(path2); + if (isAbsolute || this.hasProtocol(path2)) { + start = 1; + } else { + start = 0; + } + let startDot = -1; + let startPart = 0; + let end = -1; + let matchedSlash = true; + let i = path2.length - 1; + let preDotState = 0; + for (; i >= start; --i) { + code = path2.charCodeAt(i); + if (code === 47) { + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + matchedSlash = false; + end = i + 1; + } + if (code === 46) { + if (startDot === -1) + startDot = i; + else if (preDotState !== 1) + preDotState = 1; + } else if (startDot !== -1) { + preDotState = -1; + } + } + if (startDot === -1 || end === -1 || preDotState === 0 || preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) + ret.base = ret.name = path2.slice(1, end); + else + ret.base = ret.name = path2.slice(startPart, end); + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path2.slice(1, startDot); + ret.base = path2.slice(1, end); + } else { + ret.name = path2.slice(startPart, startDot); + ret.base = path2.slice(startPart, end); + } + ret.ext = path2.slice(startDot, end); + } + ret.dir = this.dirname(path2); + if (protocol) + ret.dir = protocol + ret.dir; + return ret; + }, + sep: "/", + delimiter: ":", + joinExtensions: [".html"] + }; + + "use strict"; + const convertToList = (input, transform, forceTransform = false) => { + if (!Array.isArray(input)) { + input = [input]; + } + if (!transform) { + return input; + } + return input.map((item) => { + if (typeof item === "string" || forceTransform) { + return transform(item); + } + return item; + }); + }; + + "use strict"; + function processX(base, ids, depth, result, tags) { + const id = ids[depth]; + for (let i = 0; i < id.length; i++) { + const value = id[i]; + if (depth < ids.length - 1) { + processX(base.replace(result[depth], value), ids, depth + 1, result, tags); + } else { + tags.push(base.replace(result[depth], value)); + } + } + } + function createStringVariations(string) { + const regex = /\{(.*?)\}/g; + const result = string.match(regex); + const tags = []; + if (result) { + const ids = []; + result.forEach((vars) => { + const split = vars.substring(1, vars.length - 1).split(","); + ids.push(split); + }); + processX(string, ids, 0, result, tags); + } else { + tags.push(string); + } + return tags; + } + + "use strict"; + const isSingleItem = (item) => !Array.isArray(item); + + "use strict"; + var __defProp$_ = Object.defineProperty; + var __getOwnPropSymbols$_ = Object.getOwnPropertySymbols; + var __hasOwnProp$_ = Object.prototype.hasOwnProperty; + var __propIsEnum$_ = Object.prototype.propertyIsEnumerable; + var __defNormalProp$_ = (obj, key, value) => key in obj ? __defProp$_(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$_ = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$_.call(b, prop)) + __defNormalProp$_(a, prop, b[prop]); + if (__getOwnPropSymbols$_) + for (var prop of __getOwnPropSymbols$_(b)) { + if (__propIsEnum$_.call(b, prop)) + __defNormalProp$_(a, prop, b[prop]); + } + return a; + }; + class Resolver { + constructor() { + this._defaultBundleIdentifierOptions = { + connector: "-", + createBundleAssetId: (bundleId, assetId) => `${bundleId}${this._bundleIdConnector}${assetId}`, + extractAssetIdFromBundle: (bundleId, assetBundleId) => assetBundleId.replace(`${bundleId}${this._bundleIdConnector}`, "") + }; + /** The character that is used to connect the bundleId and the assetId when generating a bundle asset id key */ + this._bundleIdConnector = this._defaultBundleIdentifierOptions.connector; + /** + * A function that generates a bundle asset id key from a bundleId and an assetId + * @param bundleId - the bundleId + * @param assetId - the assetId + * @returns the bundle asset id key + */ + this._createBundleAssetId = this._defaultBundleIdentifierOptions.createBundleAssetId; + /** + * A function that generates an assetId from a bundle asset id key. This is the reverse of generateBundleAssetId + * @param bundleId - the bundleId + * @param assetBundleId - the bundle asset id key + * @returns the assetId + */ + this._extractAssetIdFromBundle = this._defaultBundleIdentifierOptions.extractAssetIdFromBundle; + this._assetMap = {}; + this._preferredOrder = []; + this._parsers = []; + this._resolverHash = {}; + this._bundles = {}; + } + /** + * Override how the resolver deals with generating bundle ids. + * must be called before any bundles are added + * @param bundleIdentifier - the bundle identifier options + */ + setBundleIdentifier(bundleIdentifier) { + var _a, _b, _c; + this._bundleIdConnector = (_a = bundleIdentifier.connector) != null ? _a : this._bundleIdConnector; + this._createBundleAssetId = (_b = bundleIdentifier.createBundleAssetId) != null ? _b : this._createBundleAssetId; + this._extractAssetIdFromBundle = (_c = bundleIdentifier.extractAssetIdFromBundle) != null ? _c : this._extractAssetIdFromBundle; + if (this._extractAssetIdFromBundle("foo", this._createBundleAssetId("foo", "bar")) !== "bar") { + throw new Error("[Resolver] GenerateBundleAssetId are not working correctly"); + } + } + /** + * Let the resolver know which assets you prefer to use when resolving assets. + * Multiple prefer user defined rules can be added. + * @example + * resolver.prefer({ + * // first look for something with the correct format, and then then correct resolution + * priority: ['format', 'resolution'], + * params:{ + * format:'webp', // prefer webp images + * resolution: 2, // prefer a resolution of 2 + * } + * }) + * resolver.add('foo', ['bar@2x.webp', 'bar@2x.png', 'bar.webp', 'bar.png']); + * resolver.resolveUrl('foo') // => 'bar@2x.webp' + * @param preferOrders - the prefer options + */ + prefer(...preferOrders) { + preferOrders.forEach((prefer) => { + this._preferredOrder.push(prefer); + if (!prefer.priority) { + prefer.priority = Object.keys(prefer.params); + } + }); + this._resolverHash = {}; + } + /** + * Set the base path to prepend to all urls when resolving + * @example + * resolver.basePath = 'https://home.com/'; + * resolver.add('foo', 'bar.ong'); + * resolver.resolveUrl('foo', 'bar.png'); // => 'https://home.com/bar.png' + * @param basePath - the base path to use + */ + set basePath(basePath) { + this._basePath = basePath; + } + get basePath() { + return this._basePath; + } + /** + * Set the root path for root-relative URLs. By default the `basePath`'s root is used. If no `basePath` is set, then the + * default value for browsers is `window.location.origin` + * @example + * // Application hosted on https://home.com/some-path/index.html + * resolver.basePath = 'https://home.com/some-path/'; + * resolver.rootPath = 'https://home.com/'; + * resolver.add('foo', '/bar.png'); + * resolver.resolveUrl('foo', '/bar.png'); // => 'https://home.com/bar.png' + * @param rootPath - the root path to use + */ + set rootPath(rootPath) { + this._rootPath = rootPath; + } + get rootPath() { + return this._rootPath; + } + /** + * All the active URL parsers that help the parser to extract information and create + * an asset object-based on parsing the URL itself. + * + * Can be added using the extensions API + * @example + * resolver.add('foo', [ + * { + * resolution: 2, + * format: 'png', + * src: 'image@2x.png', + * }, + * { + * resolution:1, + * format:'png', + * src: 'image.png', + * }, + * ]); + * + * // With a url parser the information such as resolution and file format could extracted from the url itself: + * extensions.add({ + * extension: ExtensionType.ResolveParser, + * test: loadTextures.test, // test if url ends in an image + * parse: (value: string) => + * ({ + * resolution: parseFloat(Resolver.RETINA_PREFIX.exec(value)?.[1] ?? '1'), + * format: value.split('.').pop(), + * src: value, + * }), + * }); + * + * // Now resolution and format can be extracted from the url + * resolver.add('foo', [ + * 'image@2x.png', + * 'image.png', + * ]); + */ + get parsers() { + return this._parsers; + } + /** Used for testing, this resets the resolver to its initial state */ + reset() { + this.setBundleIdentifier(this._defaultBundleIdentifierOptions); + this._assetMap = {}; + this._preferredOrder = []; + this._resolverHash = {}; + this._rootPath = null; + this._basePath = null; + this._manifest = null; + this._bundles = {}; + this._defaultSearchParams = null; + } + /** + * Sets the default URL search parameters for the URL resolver. The urls can be specified as a string or an object. + * @param searchParams - the default url parameters to append when resolving urls + */ + setDefaultSearchParams(searchParams) { + if (typeof searchParams === "string") { + this._defaultSearchParams = searchParams; + } else { + const queryValues = searchParams; + this._defaultSearchParams = Object.keys(queryValues).map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(queryValues[key])}`).join("&"); + } + } + /** + * Returns the aliases for a given asset + * @param asset - the asset to get the aliases for + */ + getAlias(asset) { + const { alias, src } = asset; + const aliasesToUse = convertToList( + alias || src, + (value) => { + if (typeof value === "string") + return value; + if (Array.isArray(value)) + return value.map((v) => { + var _a; + return (_a = v == null ? void 0 : v.src) != null ? _a : v; + }); + if (value == null ? void 0 : value.src) + return value.src; + return value; + }, + true + ); + return aliasesToUse; + } + /** + * Add a manifest to the asset resolver. This is a nice way to add all the asset information in one go. + * generally a manifest would be built using a tool. + * @param manifest - the manifest to add to the resolver + */ + addManifest(manifest) { + if (this._manifest) { + warn("[Resolver] Manifest already exists, this will be overwritten"); + } + this._manifest = manifest; + manifest.bundles.forEach((bundle) => { + this.addBundle(bundle.name, bundle.assets); + }); + } + /** + * This adds a bundle of assets in one go so that you can resolve them as a group. + * For example you could add a bundle for each screen in you pixi app + * @example + * resolver.addBundle('animals', [ + * { alias: 'bunny', src: 'bunny.png' }, + * { alias: 'chicken', src: 'chicken.png' }, + * { alias: 'thumper', src: 'thumper.png' }, + * ]); + * // or + * resolver.addBundle('animals', { + * bunny: 'bunny.png', + * chicken: 'chicken.png', + * thumper: 'thumper.png', + * }); + * + * const resolvedAssets = await resolver.resolveBundle('animals'); + * @param bundleId - The id of the bundle to add + * @param assets - A record of the asset or assets that will be chosen from when loading via the specified key + */ + addBundle(bundleId, assets) { + const assetNames = []; + let convertedAssets = assets; + if (!Array.isArray(assets)) { + convertedAssets = Object.entries(assets).map(([alias, src]) => { + if (typeof src === "string" || Array.isArray(src)) { + return { alias, src }; + } + return __spreadValues$_({ alias }, src); + }); + } + convertedAssets.forEach((asset) => { + const srcs = asset.src; + const aliases = asset.alias; + let ids; + if (typeof aliases === "string") { + const bundleAssetId = this._createBundleAssetId(bundleId, aliases); + assetNames.push(bundleAssetId); + ids = [aliases, bundleAssetId]; + } else { + const bundleIds = aliases.map((name) => this._createBundleAssetId(bundleId, name)); + assetNames.push(...bundleIds); + ids = [...aliases, ...bundleIds]; + } + this.add(__spreadValues$_(__spreadValues$_({}, asset), { + alias: ids, + src: srcs + })); + }); + this._bundles[bundleId] = assetNames; + } + /** + * Tells the resolver what keys are associated with witch asset. + * The most important thing the resolver does + * @example + * // Single key, single asset: + * resolver.add({alias: 'foo', src: 'bar.png'); + * resolver.resolveUrl('foo') // => 'bar.png' + * + * // Multiple keys, single asset: + * resolver.add({alias: ['foo', 'boo'], src: 'bar.png'}); + * resolver.resolveUrl('foo') // => 'bar.png' + * resolver.resolveUrl('boo') // => 'bar.png' + * + * // Multiple keys, multiple assets: + * resolver.add({alias: ['foo', 'boo'], src: ['bar.png', 'bar.webp']}); + * resolver.resolveUrl('foo') // => 'bar.png' + * + * // Add custom data attached to the resolver + * Resolver.add({ + * alias: 'bunnyBooBooSmooth', + * src: 'bunny{png,webp}', + * data: { scaleMode:SCALE_MODES.NEAREST }, // Base texture options + * }); + * + * resolver.resolve('bunnyBooBooSmooth') // => { src: 'bunny.png', data: { scaleMode: SCALE_MODES.NEAREST } } + * @param aliases - the UnresolvedAsset or array of UnresolvedAssets to add to the resolver + */ + add(aliases) { + const assets = []; + if (Array.isArray(aliases)) { + assets.push(...aliases); + } else { + assets.push(aliases); + } + let keyCheck; + keyCheck = (key) => { + if (this.hasKey(key)) { + warn(`[Resolver] already has key: ${key} overwriting`); + } + }; + const assetArray = convertToList(assets); + assetArray.forEach((asset) => { + const { src } = asset; + let { data, format, loadParser } = asset; + const srcsToUse = convertToList(src).map((src2) => { + if (typeof src2 === "string") { + return createStringVariations(src2); + } + return Array.isArray(src2) ? src2 : [src2]; + }); + const aliasesToUse = this.getAlias(asset); + Array.isArray(aliasesToUse) ? aliasesToUse.forEach(keyCheck) : keyCheck(aliasesToUse); + const resolvedAssets = []; + srcsToUse.forEach((srcs) => { + srcs.forEach((src2) => { + var _a, _b, _c; + let formattedAsset = {}; + if (typeof src2 !== "object") { + formattedAsset.src = src2; + for (let i = 0; i < this._parsers.length; i++) { + const parser = this._parsers[i]; + if (parser.test(src2)) { + formattedAsset = parser.parse(src2); + break; + } + } + } else { + data = (_a = src2.data) != null ? _a : data; + format = (_b = src2.format) != null ? _b : format; + loadParser = (_c = src2.loadParser) != null ? _c : loadParser; + formattedAsset = __spreadValues$_(__spreadValues$_({}, formattedAsset), src2); + } + if (!aliasesToUse) { + throw new Error(`[Resolver] alias is undefined for this asset: ${formattedAsset.src}`); + } + formattedAsset = this._buildResolvedAsset(formattedAsset, { + aliases: aliasesToUse, + data, + format, + loadParser + }); + resolvedAssets.push(formattedAsset); + }); + }); + aliasesToUse.forEach((alias) => { + this._assetMap[alias] = resolvedAssets; + }); + }); + } + // TODO: this needs an overload like load did in Assets + /** + * If the resolver has had a manifest set via setManifest, this will return the assets urls for + * a given bundleId or bundleIds. + * @example + * // Manifest Example + * const manifest = { + * bundles: [ + * { + * name: 'load-screen', + * assets: [ + * { + * alias: 'background', + * src: 'sunset.png', + * }, + * { + * alias: 'bar', + * src: 'load-bar.{png,webp}', + * }, + * ], + * }, + * { + * name: 'game-screen', + * assets: [ + * { + * alias: 'character', + * src: 'robot.png', + * }, + * { + * alias: 'enemy', + * src: 'bad-guy.png', + * }, + * ], + * }, + * ] + * }; + * + * resolver.setManifest(manifest); + * const resolved = resolver.resolveBundle('load-screen'); + * @param bundleIds - The bundle ids to resolve + * @returns All the bundles assets or a hash of assets for each bundle specified + */ + resolveBundle(bundleIds) { + const singleAsset = isSingleItem(bundleIds); + bundleIds = convertToList(bundleIds); + const out = {}; + bundleIds.forEach((bundleId) => { + const assetNames = this._bundles[bundleId]; + if (assetNames) { + const results = this.resolve(assetNames); + const assets = {}; + for (const key in results) { + const asset = results[key]; + assets[this._extractAssetIdFromBundle(bundleId, key)] = asset; + } + out[bundleId] = assets; + } + }); + return singleAsset ? out[bundleIds[0]] : out; + } + /** + * Does exactly what resolve does, but returns just the URL rather than the whole asset object + * @param key - The key or keys to resolve + * @returns - The URLs associated with the key(s) + */ + resolveUrl(key) { + const result = this.resolve(key); + if (typeof key !== "string") { + const out = {}; + for (const i in result) { + out[i] = result[i].src; + } + return out; + } + return result.src; + } + resolve(keys) { + const singleAsset = isSingleItem(keys); + keys = convertToList(keys); + const result = {}; + keys.forEach((key) => { + if (!this._resolverHash[key]) { + if (this._assetMap[key]) { + let assets = this._assetMap[key]; + const preferredOrder = this._getPreferredOrder(assets); + preferredOrder == null ? void 0 : preferredOrder.priority.forEach((priorityKey) => { + preferredOrder.params[priorityKey].forEach((value) => { + const filteredAssets = assets.filter((asset) => { + if (asset[priorityKey]) { + return asset[priorityKey] === value; + } + return false; + }); + if (filteredAssets.length) { + assets = filteredAssets; + } + }); + }); + this._resolverHash[key] = assets[0]; + } else { + this._resolverHash[key] = this._buildResolvedAsset({ + alias: [key], + src: key + }, {}); + } + } + result[key] = this._resolverHash[key]; + }); + return singleAsset ? result[keys[0]] : result; + } + /** + * Checks if an asset with a given key exists in the resolver + * @param key - The key of the asset + */ + hasKey(key) { + return !!this._assetMap[key]; + } + /** + * Checks if a bundle with the given key exists in the resolver + * @param key - The key of the bundle + */ + hasBundle(key) { + return !!this._bundles[key]; + } + /** + * Internal function for figuring out what prefer criteria an asset should use. + * @param assets + */ + _getPreferredOrder(assets) { + for (let i = 0; i < assets.length; i++) { + const asset = assets[0]; + const preferred = this._preferredOrder.find((preference) => preference.params.format.includes(asset.format)); + if (preferred) { + return preferred; + } + } + return this._preferredOrder[0]; + } + /** + * Appends the default url parameters to the url + * @param url - The url to append the default parameters to + * @returns - The url with the default parameters appended + */ + _appendDefaultSearchParams(url) { + if (!this._defaultSearchParams) + return url; + const paramConnector = /\?/.test(url) ? "&" : "?"; + return `${url}${paramConnector}${this._defaultSearchParams}`; + } + _buildResolvedAsset(formattedAsset, data) { + var _a, _b; + const { aliases, data: assetData, loadParser, format } = data; + if (this._basePath || this._rootPath) { + formattedAsset.src = path.toAbsolute(formattedAsset.src, this._basePath, this._rootPath); + } + formattedAsset.alias = (_a = aliases != null ? aliases : formattedAsset.alias) != null ? _a : [formattedAsset.src]; + formattedAsset.src = this._appendDefaultSearchParams(formattedAsset.src); + formattedAsset.data = __spreadValues$_(__spreadValues$_({}, assetData || {}), formattedAsset.data); + formattedAsset.loadParser = loadParser != null ? loadParser : formattedAsset.loadParser; + formattedAsset.format = (_b = format != null ? format : formattedAsset.format) != null ? _b : getUrlExtension(formattedAsset.src); + return formattedAsset; + } + } + /** + * The prefix that denotes a URL is for a retina asset. + * @static + * @name RETINA_PREFIX + * @type {RegExp} + * @default /@([0-9\.]+)x/ + * @example `@2x` + */ + Resolver.RETINA_PREFIX = /@([0-9\.]+)x/; + function getUrlExtension(url) { + return url.split(".").pop().split("?").shift().split("#").shift(); + } + + "use strict"; + const copySearchParams = (targetUrl, sourceUrl) => { + const searchParams = sourceUrl.split("?")[1]; + if (searchParams) { + targetUrl += `?${searchParams}`; + } + return targetUrl; + }; + + "use strict"; + const ux = [1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1, 0, 1]; + const uy = [0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1]; + const vx = [0, -1, -1, -1, 0, 1, 1, 1, 0, 1, 1, 1, 0, -1, -1, -1]; + const vy = [1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1]; + const rotationCayley = []; + const rotationMatrices = []; + const signum = Math.sign; + function init() { + for (let i = 0; i < 16; i++) { + const row = []; + rotationCayley.push(row); + for (let j = 0; j < 16; j++) { + const _ux = signum(ux[i] * ux[j] + vx[i] * uy[j]); + const _uy = signum(uy[i] * ux[j] + vy[i] * uy[j]); + const _vx = signum(ux[i] * vx[j] + vx[i] * vy[j]); + const _vy = signum(uy[i] * vx[j] + vy[i] * vy[j]); + for (let k = 0; k < 16; k++) { + if (ux[k] === _ux && uy[k] === _uy && vx[k] === _vx && vy[k] === _vy) { + row.push(k); + break; + } + } + } + } + for (let i = 0; i < 16; i++) { + const mat = new Matrix(); + mat.set(ux[i], uy[i], vx[i], vy[i], 0, 0); + rotationMatrices.push(mat); + } + } + init(); + const groupD8 = { + /** + * | Rotation | Direction | + * |----------|-----------| + * | 0° | East | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + E: 0, + /** + * | Rotation | Direction | + * |----------|-----------| + * | 45°↻ | Southeast | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + SE: 1, + /** + * | Rotation | Direction | + * |----------|-----------| + * | 90°↻ | South | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + S: 2, + /** + * | Rotation | Direction | + * |----------|-----------| + * | 135°↻ | Southwest | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + SW: 3, + /** + * | Rotation | Direction | + * |----------|-----------| + * | 180° | West | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + W: 4, + /** + * | Rotation | Direction | + * |-------------|--------------| + * | -135°/225°↻ | Northwest | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + NW: 5, + /** + * | Rotation | Direction | + * |-------------|--------------| + * | -90°/270°↻ | North | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + N: 6, + /** + * | Rotation | Direction | + * |-------------|--------------| + * | -45°/315°↻ | Northeast | + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + NE: 7, + /** + * Reflection about Y-axis. + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + MIRROR_VERTICAL: 8, + /** + * Reflection about the main diagonal. + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + MAIN_DIAGONAL: 10, + /** + * Reflection about X-axis. + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + MIRROR_HORIZONTAL: 12, + /** + * Reflection about reverse diagonal. + * @memberof maths.groupD8 + * @constant {GD8Symmetry} + */ + REVERSE_DIAGONAL: 14, + /** + * @memberof maths.groupD8 + * @param {GD8Symmetry} ind - sprite rotation angle. + * @returns {GD8Symmetry} The X-component of the U-axis + * after rotating the axes. + */ + uX: (ind) => ux[ind], + /** + * @memberof maths.groupD8 + * @param {GD8Symmetry} ind - sprite rotation angle. + * @returns {GD8Symmetry} The Y-component of the U-axis + * after rotating the axes. + */ + uY: (ind) => uy[ind], + /** + * @memberof maths.groupD8 + * @param {GD8Symmetry} ind - sprite rotation angle. + * @returns {GD8Symmetry} The X-component of the V-axis + * after rotating the axes. + */ + vX: (ind) => vx[ind], + /** + * @memberof maths.groupD8 + * @param {GD8Symmetry} ind - sprite rotation angle. + * @returns {GD8Symmetry} The Y-component of the V-axis + * after rotating the axes. + */ + vY: (ind) => vy[ind], + /** + * @memberof maths.groupD8 + * @param {GD8Symmetry} rotation - symmetry whose opposite + * is needed. Only rotations have opposite symmetries while + * reflections don't. + * @returns {GD8Symmetry} The opposite symmetry of `rotation` + */ + inv: (rotation) => { + if (rotation & 8) { + return rotation & 15; + } + return -rotation & 7; + }, + /** + * Composes the two D8 operations. + * + * Taking `^` as reflection: + * + * | | E=0 | S=2 | W=4 | N=6 | E^=8 | S^=10 | W^=12 | N^=14 | + * |-------|-----|-----|-----|-----|------|-------|-------|-------| + * | E=0 | E | S | W | N | E^ | S^ | W^ | N^ | + * | S=2 | S | W | N | E | S^ | W^ | N^ | E^ | + * | W=4 | W | N | E | S | W^ | N^ | E^ | S^ | + * | N=6 | N | E | S | W | N^ | E^ | S^ | W^ | + * | E^=8 | E^ | N^ | W^ | S^ | E | N | W | S | + * | S^=10 | S^ | E^ | N^ | W^ | S | E | N | W | + * | W^=12 | W^ | S^ | E^ | N^ | W | S | E | N | + * | N^=14 | N^ | W^ | S^ | E^ | N | W | S | E | + * + * [This is a Cayley table]{@link https://en.wikipedia.org/wiki/Cayley_table} + * @memberof maths.groupD8 + * @param {GD8Symmetry} rotationSecond - Second operation, which + * is the row in the above cayley table. + * @param {GD8Symmetry} rotationFirst - First operation, which + * is the column in the above cayley table. + * @returns {GD8Symmetry} Composed operation + */ + add: (rotationSecond, rotationFirst) => rotationCayley[rotationSecond][rotationFirst], + /** + * Reverse of `add`. + * @memberof maths.groupD8 + * @param {GD8Symmetry} rotationSecond - Second operation + * @param {GD8Symmetry} rotationFirst - First operation + * @returns {GD8Symmetry} Result + */ + sub: (rotationSecond, rotationFirst) => rotationCayley[rotationSecond][groupD8.inv(rotationFirst)], + /** + * Adds 180 degrees to rotation, which is a commutative + * operation. + * @memberof maths.groupD8 + * @param {number} rotation - The number to rotate. + * @returns {number} Rotated number + */ + rotate180: (rotation) => rotation ^ 4, + /** + * Checks if the rotation angle is vertical, i.e. south + * or north. It doesn't work for reflections. + * @memberof maths.groupD8 + * @param {GD8Symmetry} rotation - The number to check. + * @returns {boolean} Whether or not the direction is vertical + */ + isVertical: (rotation) => (rotation & 3) === 2, + // rotation % 4 === 2 + /** + * Approximates the vector `V(dx,dy)` into one of the + * eight directions provided by `groupD8`. + * @memberof maths.groupD8 + * @param {number} dx - X-component of the vector + * @param {number} dy - Y-component of the vector + * @returns {GD8Symmetry} Approximation of the vector into + * one of the eight symmetries. + */ + byDirection: (dx, dy) => { + if (Math.abs(dx) * 2 <= Math.abs(dy)) { + if (dy >= 0) { + return groupD8.S; + } + return groupD8.N; + } else if (Math.abs(dy) * 2 <= Math.abs(dx)) { + if (dx > 0) { + return groupD8.E; + } + return groupD8.W; + } else if (dy > 0) { + if (dx > 0) { + return groupD8.SE; + } + return groupD8.SW; + } else if (dx > 0) { + return groupD8.NE; + } + return groupD8.NW; + }, + /** + * Helps sprite to compensate texture packer rotation. + * @memberof maths.groupD8 + * @param {Matrix} matrix - sprite world matrix + * @param {GD8Symmetry} rotation - The rotation factor to use. + * @param {number} tx - sprite anchoring + * @param {number} ty - sprite anchoring + */ + matrixAppendRotationInv: (matrix, rotation, tx = 0, ty = 0) => { + const mat = rotationMatrices[groupD8.inv(rotation)]; + mat.tx = tx; + mat.ty = ty; + matrix.append(mat); + } + }; + + "use strict"; + const NOOP = () => { + }; + + "use strict"; + function nextPow2(v) { + v += v === 0 ? 1 : 0; + --v; + v |= v >>> 1; + v |= v >>> 2; + v |= v >>> 4; + v |= v >>> 8; + v |= v >>> 16; + return v + 1; + } + function isPow2(v) { + return !(v & v - 1) && !!v; + } + function log2(v) { + let r = (v > 65535 ? 1 : 0) << 4; + v >>>= r; + let shift = (v > 255 ? 1 : 0) << 3; + v >>>= shift; + r |= shift; + shift = (v > 15 ? 1 : 0) << 2; + v >>>= shift; + r |= shift; + shift = (v > 3 ? 1 : 0) << 1; + v >>>= shift; + r |= shift; + return r | v >> 1; + } + + "use strict"; + function definedProps(obj) { + const result = {}; + for (const key in obj) { + if (obj[key] !== void 0) { + result[key] = obj[key]; + } + } + return result; + } + + "use strict"; + var __defProp$Z = Object.defineProperty; + var __getOwnPropSymbols$Z = Object.getOwnPropertySymbols; + var __hasOwnProp$Z = Object.prototype.hasOwnProperty; + var __propIsEnum$Z = Object.prototype.propertyIsEnumerable; + var __defNormalProp$Z = (obj, key, value) => key in obj ? __defProp$Z(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$Z = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$Z.call(b, prop)) + __defNormalProp$Z(a, prop, b[prop]); + if (__getOwnPropSymbols$Z) + for (var prop of __getOwnPropSymbols$Z(b)) { + if (__propIsEnum$Z.call(b, prop)) + __defNormalProp$Z(a, prop, b[prop]); + } + return a; + }; + const idHash$1 = /* @__PURE__ */ Object.create(null); + function createResourceIdFromString(value) { + const id = idHash$1[value]; + if (id === void 0) { + idHash$1[value] = uid("resource"); + } + return id; + } + const _TextureStyle = class _TextureStyle extends EventEmitter { + /** + * @param options - options for the style + */ + constructor(options = {}) { + var _a, _b, _c, _d, _e, _f, _g; + super(); + this._resourceType = "textureSampler"; + this._touched = 0; + /** + * Specifies the maximum anisotropy value clamp used by the sampler. + * Note: Most implementations support {@link GPUSamplerDescriptor#maxAnisotropy} values in range + * between 1 and 16, inclusive. The used value of {@link GPUSamplerDescriptor#maxAnisotropy} will + * be clamped to the maximum value that the platform supports. + * @internal + * @ignore + */ + this._maxAnisotropy = 1; + /** + * Has the style been destroyed? + * @readonly + */ + this.destroyed = false; + options = __spreadValues$Z(__spreadValues$Z({}, _TextureStyle.defaultOptions), options); + this.addressMode = options.addressMode; + this.addressModeU = (_a = options.addressModeU) != null ? _a : this.addressModeU; + this.addressModeV = (_b = options.addressModeV) != null ? _b : this.addressModeV; + this.addressModeW = (_c = options.addressModeW) != null ? _c : this.addressModeW; + this.scaleMode = options.scaleMode; + this.magFilter = (_d = options.magFilter) != null ? _d : this.magFilter; + this.minFilter = (_e = options.minFilter) != null ? _e : this.minFilter; + this.mipmapFilter = (_f = options.mipmapFilter) != null ? _f : this.mipmapFilter; + this.lodMinClamp = options.lodMinClamp; + this.lodMaxClamp = options.lodMaxClamp; + this.compare = options.compare; + this.maxAnisotropy = (_g = options.maxAnisotropy) != null ? _g : 1; + } + set addressMode(value) { + this.addressModeU = value; + this.addressModeV = value; + this.addressModeW = value; + } + /** setting this will set wrapModeU,wrapModeV and wrapModeW all at once! */ + get addressMode() { + return this.addressModeU; + } + set wrapMode(value) { + deprecation(v8_0_0, "TextureStyle.wrapMode is now TextureStyle.addressMode"); + this.addressMode = value; + } + get wrapMode() { + return this.addressMode; + } + set scaleMode(value) { + this.magFilter = value; + this.minFilter = value; + this.mipmapFilter = value; + } + /** setting this will set magFilter,minFilter and mipmapFilter all at once! */ + get scaleMode() { + return this.magFilter; + } + /** Specifies the maximum anisotropy value clamp used by the sampler. */ + set maxAnisotropy(value) { + this._maxAnisotropy = Math.min(value, 16); + if (this._maxAnisotropy > 1) { + this.scaleMode = "linear"; + } + } + get maxAnisotropy() { + return this._maxAnisotropy; + } + // TODO - move this to WebGL? + get _resourceId() { + return this._sharedResourceId || this._generateResourceId(); + } + update() { + this.emit("change", this); + this._sharedResourceId = null; + } + _generateResourceId() { + const bigKey = `${this.addressModeU}-${this.addressModeV}-${this.addressModeW}-${this.magFilter}-${this.minFilter}-${this.mipmapFilter}-${this.lodMinClamp}-${this.lodMaxClamp}-${this.compare}-${this._maxAnisotropy}`; + this._sharedResourceId = createResourceIdFromString(bigKey); + return this._resourceId; + } + /** Destroys the style */ + destroy() { + this.destroyed = true; + this.emit("destroy", this); + this.emit("change", this); + this.removeAllListeners(); + } + }; + /** default options for the style */ + _TextureStyle.defaultOptions = { + addressMode: "clamp-to-edge", + scaleMode: "linear" + }; + let TextureStyle = _TextureStyle; + + "use strict"; + var __defProp$Y = Object.defineProperty; + var __getOwnPropSymbols$Y = Object.getOwnPropertySymbols; + var __hasOwnProp$Y = Object.prototype.hasOwnProperty; + var __propIsEnum$Y = Object.prototype.propertyIsEnumerable; + var __defNormalProp$Y = (obj, key, value) => key in obj ? __defProp$Y(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$Y = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$Y.call(b, prop)) + __defNormalProp$Y(a, prop, b[prop]); + if (__getOwnPropSymbols$Y) + for (var prop of __getOwnPropSymbols$Y(b)) { + if (__propIsEnum$Y.call(b, prop)) + __defNormalProp$Y(a, prop, b[prop]); + } + return a; + }; + const _TextureSource = class _TextureSource extends EventEmitter { + /** + * @param options - options for creating a new TextureSource + */ + constructor(options = {}) { + var _a, _b, _c; + super(); + this.options = options; + /** unique id for this Texture source */ + this.uid = uid("textureSource"); + /** + * The resource type used by this TextureSource. This is used by the bind groups to determine + * how to handle this resource. + * @ignore + * @internal + */ + this._resourceType = "textureSource"; + /** + * i unique resource id, used by the bind group systems. + * This can change if the texture is resized or its resource changes + */ + this._resourceId = uid("resource"); + /** + * this is how the backends know how to upload this texture to the GPU + * It changes depending on the resource type. Classes that extend TextureSource + * should override this property. + * @ignore + * @internal + */ + this.uploadMethodId = "unknown"; + // dimensions + this._resolution = 1; + /** the pixel width of this texture source. This is the REAL pure number, not accounting resolution */ + this.pixelWidth = 1; + /** the pixel height of this texture source. This is the REAL pure number, not accounting resolution */ + this.pixelHeight = 1; + /** + * the width of this texture source, accounting for resolution + * eg pixelWidth 200, resolution 2, then width will be 100 + */ + this.width = 1; + /** + * the height of this texture source, accounting for resolution + * eg pixelHeight 200, resolution 2, then height will be 100 + */ + this.height = 1; + /** + * The number of samples of a multisample texture. This is always 1 for non-multisample textures. + * To enable multisample for a texture, set antialias to true + * @internal + * @ignore + */ + this.sampleCount = 1; + /** The number of mip levels to generate for this texture. this is overridden if autoGenerateMipmaps is true */ + this.mipLevelCount = 1; + /** + * Should we auto generate mipmaps for this texture? This will automatically generate mipmaps + * for this texture when uploading to the GPU. Mipmapped textures take up more memory, but + * can look better when scaled down. + * + * For performance reasons, it is recommended to NOT use this with RenderTextures, as they are often updated every frame. + * If you do, make sure to call `updateMipmaps` after you update the texture. + */ + this.autoGenerateMipmaps = false; + /** the format that the texture data has */ + this.format = "rgba8unorm"; + /** how many dimensions does this texture have? currently v8 only supports 2d */ + this.dimension = "2d"; + /** + * Only really affects RenderTextures. + * Should we use antialiasing for this texture. It will look better, but may impact performance as a + * Blit operation will be required to resolve the texture. + */ + this.antialias = false; + /** + * Used by automatic texture Garbage Collection, stores last GC tick when it was bound + * @protected + */ + this._touched = 0; + /** + * Used by the batcher to build texture batches. faster to have the variable here! + * @protected + */ + this._batchTick = -1; + /** + * A temporary batch location for the texture batching. Here for performance reasons only! + * @protected + */ + this._textureBindLocation = -1; + options = __spreadValues$Y(__spreadValues$Y({}, _TextureSource.defaultOptions), options); + this.label = (_a = options.label) != null ? _a : ""; + this.resource = options.resource; + this.autoGarbageCollect = options.autoGarbageCollect; + this._resolution = options.resolution; + if (options.width) { + this.pixelWidth = options.width * this._resolution; + } else { + this.pixelWidth = this.resource ? (_b = this.resourceWidth) != null ? _b : 1 : 1; + } + if (options.height) { + this.pixelHeight = options.height * this._resolution; + } else { + this.pixelHeight = this.resource ? (_c = this.resourceHeight) != null ? _c : 1 : 1; + } + this.width = this.pixelWidth / this._resolution; + this.height = this.pixelHeight / this._resolution; + this.format = options.format; + this.dimension = options.dimensions; + this.mipLevelCount = options.mipLevelCount; + this.autoGenerateMipmaps = options.autoGenerateMipmaps; + this.sampleCount = options.sampleCount; + this.antialias = options.antialias; + this.alphaMode = options.alphaMode; + this.style = new TextureStyle(definedProps(options)); + this.destroyed = false; + this._refreshPOT(); + } + /** returns itself */ + get source() { + return this; + } + /** the style of the texture */ + get style() { + return this._style; + } + set style(value) { + var _a, _b; + if (this.style === value) + return; + (_a = this._style) == null ? void 0 : _a.off("change", this._onStyleChange, this); + this._style = value; + (_b = this._style) == null ? void 0 : _b.on("change", this._onStyleChange, this); + this._onStyleChange(); + } + /** setting this will set wrapModeU,wrapModeV and wrapModeW all at once! */ + get addressMode() { + return this._style.addressMode; + } + set addressMode(value) { + this._style.addressMode = value; + } + /** setting this will set wrapModeU,wrapModeV and wrapModeW all at once! */ + get repeatMode() { + return this._style.addressMode; + } + set repeatMode(value) { + this._style.addressMode = value; + } + /** Specifies the sampling behavior when the sample footprint is smaller than or equal to one texel. */ + get magFilter() { + return this._style.magFilter; + } + set magFilter(value) { + this._style.magFilter = value; + } + /** Specifies the sampling behavior when the sample footprint is larger than one texel. */ + get minFilter() { + return this._style.minFilter; + } + set minFilter(value) { + this._style.minFilter = value; + } + /** Specifies behavior for sampling between mipmap levels. */ + get mipmapFilter() { + return this._style.mipmapFilter; + } + set mipmapFilter(value) { + this._style.mipmapFilter = value; + } + /** Specifies the minimum and maximum levels of detail, respectively, used internally when sampling a texture. */ + get lodMinClamp() { + return this._style.lodMinClamp; + } + set lodMinClamp(value) { + this._style.lodMinClamp = value; + } + /** Specifies the minimum and maximum levels of detail, respectively, used internally when sampling a texture. */ + get lodMaxClamp() { + return this._style.lodMaxClamp; + } + set lodMaxClamp(value) { + this._style.lodMaxClamp = value; + } + _onStyleChange() { + this.emit("styleChange", this); + } + /** call this if you have modified the texture outside of the constructor */ + update() { + if (this.resource) { + const resolution = this._resolution; + const didResize = this.resize(this.resourceWidth / resolution, this.resourceHeight / resolution); + if (didResize) + return; + } + this.emit("update", this); + } + /** Destroys this texture source */ + destroy() { + this.destroyed = true; + this.emit("destroy", this); + this.emit("change", this); + if (this._style) { + this._style.destroy(); + this._style = null; + } + this.uploadMethodId = null; + this.resource = null; + this.removeAllListeners(); + } + /** + * This will unload the Texture source from the GPU. This will free up the GPU memory + * As soon as it is required fore rendering, it will be re-uploaded. + */ + unload() { + this._resourceId = uid("resource"); + this.emit("change", this); + this.emit("unload", this); + } + /** the width of the resource. This is the REAL pure number, not accounting resolution */ + get resourceWidth() { + const { resource } = this; + return resource.naturalWidth || resource.videoWidth || resource.displayWidth || resource.width; + } + /** the height of the resource. This is the REAL pure number, not accounting resolution */ + get resourceHeight() { + const { resource } = this; + return resource.naturalHeight || resource.videoHeight || resource.displayHeight || resource.height; + } + /** + * the resolution of the texture. Changing this number, will not change the number of pixels in the actual texture + * but will the size of the texture when rendered. + * + * changing the resolution of this texture to 2 for example will make it appear twice as small when rendered (as pixel + * density will have increased) + */ + get resolution() { + return this._resolution; + } + set resolution(resolution) { + if (this._resolution === resolution) + return; + this._resolution = resolution; + this.width = this.pixelWidth / resolution; + this.height = this.pixelHeight / resolution; + } + /** + * Resize the texture, this is handy if you want to use the texture as a render texture + * @param width - the new width of the texture + * @param height - the new height of the texture + * @param resolution - the new resolution of the texture + * @returns - if the texture was resized + */ + resize(width, height, resolution) { + resolution = resolution || this._resolution; + width = width || this.width; + height = height || this.height; + const newPixelWidth = Math.round(width * resolution); + const newPixelHeight = Math.round(height * resolution); + this.width = newPixelWidth / resolution; + this.height = newPixelHeight / resolution; + this._resolution = resolution; + if (this.pixelWidth === newPixelWidth && this.pixelHeight === newPixelHeight) { + return false; + } + this._refreshPOT(); + this.pixelWidth = newPixelWidth; + this.pixelHeight = newPixelHeight; + this.emit("resize", this); + this._resourceId = uid("resource"); + this.emit("change", this); + return true; + } + /** + * Lets the renderer know that this texture has been updated and its mipmaps should be re-generated. + * This is only important for RenderTexture instances, as standard Texture instances will have their + * mipmaps generated on upload. You should call this method after you make any change to the texture + * + * The reason for this is is can be quite expensive to update mipmaps for a texture. So by default, + * We want you, the developer to specify when this action should happen. + * + * Generally you don't want to have mipmaps generated on Render targets that are changed every frame, + */ + updateMipmaps() { + if (this.autoGenerateMipmaps && this.mipLevelCount > 1) { + this.emit("updateMipmaps", this); + } + } + set wrapMode(value) { + this._style.wrapMode = value; + } + get wrapMode() { + return this._style.wrapMode; + } + set scaleMode(value) { + this._style.scaleMode = value; + } + /** setting this will set magFilter,minFilter and mipmapFilter all at once! */ + get scaleMode() { + return this._style.scaleMode; + } + /** + * Refresh check for isPowerOfTwo texture based on size + * @private + */ + _refreshPOT() { + this.isPowerOfTwo = isPow2(this.pixelWidth) && isPow2(this.pixelHeight); + } + static test(_resource) { + throw new Error("Unimplemented"); + } + }; + /** The default options used when creating a new TextureSource. override these to add your own defaults */ + _TextureSource.defaultOptions = { + resolution: 1, + format: "bgra8unorm", + alphaMode: "premultiply-alpha-on-upload", + dimensions: "2d", + mipLevelCount: 1, + autoGenerateMipmaps: false, + sampleCount: 1, + antialias: false, + autoGarbageCollect: false + }; + let TextureSource = _TextureSource; + + "use strict"; + var __defProp$X = Object.defineProperty; + var __defProps$m = Object.defineProperties; + var __getOwnPropDescs$m = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$X = Object.getOwnPropertySymbols; + var __hasOwnProp$X = Object.prototype.hasOwnProperty; + var __propIsEnum$X = Object.prototype.propertyIsEnumerable; + var __defNormalProp$X = (obj, key, value) => key in obj ? __defProp$X(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$X = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$X.call(b, prop)) + __defNormalProp$X(a, prop, b[prop]); + if (__getOwnPropSymbols$X) + for (var prop of __getOwnPropSymbols$X(b)) { + if (__propIsEnum$X.call(b, prop)) + __defNormalProp$X(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$m = (a, b) => __defProps$m(a, __getOwnPropDescs$m(b)); + class BufferImageSource extends TextureSource { + constructor(options) { + const buffer = options.resource || new Float32Array(options.width * options.height * 4); + let format = options.format; + if (!format) { + if (buffer instanceof Float32Array) { + format = "rgba32float"; + } else if (buffer instanceof Int32Array) { + format = "rgba32uint"; + } else if (buffer instanceof Uint32Array) { + format = "rgba32uint"; + } else if (buffer instanceof Int16Array) { + format = "rgba16uint"; + } else if (buffer instanceof Uint16Array) { + format = "rgba16uint"; + } else if (buffer instanceof Int8Array) { + format = "bgra8unorm"; + } else { + format = "bgra8unorm"; + } + } + super(__spreadProps$m(__spreadValues$X({}, options), { + resource: buffer, + format + })); + this.uploadMethodId = "buffer"; + } + static test(resource) { + return resource instanceof Int8Array || resource instanceof Uint8Array || resource instanceof Uint8ClampedArray || resource instanceof Int16Array || resource instanceof Uint16Array || resource instanceof Int32Array || resource instanceof Uint32Array || resource instanceof Float32Array; + } + } + BufferImageSource.extension = ExtensionType.TextureSource; + + "use strict"; + const tempMat = new Matrix(); + class TextureMatrix { + /** + * @param texture - observed texture + * @param clampMargin - Changes frame clamping, 0.5 by default. Use -0.5 for extra border. + */ + constructor(texture, clampMargin) { + this.mapCoord = new Matrix(); + this.uClampFrame = new Float32Array(4); + this.uClampOffset = new Float32Array(2); + this._textureID = -1; + this._updateID = 0; + this.clampOffset = 0; + if (typeof clampMargin === "undefined") { + this.clampMargin = texture.width < 10 ? 0 : 0.5; + } else { + this.clampMargin = clampMargin; + } + this.isSimple = false; + this.texture = texture; + } + /** Texture property. */ + get texture() { + return this._texture; + } + set texture(value) { + var _a; + if (this.texture === value) + return; + (_a = this._texture) == null ? void 0 : _a.removeListener("update", this.update, this); + this._texture = value; + this._texture.addListener("update", this.update, this); + this.update(); + } + /** + * Multiplies uvs array to transform + * @param uvs - mesh uvs + * @param [out=uvs] - output + * @returns - output + */ + multiplyUvs(uvs, out) { + if (out === void 0) { + out = uvs; + } + const mat = this.mapCoord; + for (let i = 0; i < uvs.length; i += 2) { + const x = uvs[i]; + const y = uvs[i + 1]; + out[i] = x * mat.a + y * mat.c + mat.tx; + out[i + 1] = x * mat.b + y * mat.d + mat.ty; + } + return out; + } + /** + * Updates matrices if texture was changed + * @returns - whether or not it was updated + */ + update() { + const tex = this._texture; + this._updateID++; + const uvs = tex.uvs; + this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0); + const orig = tex.orig; + const trim = tex.trim; + if (trim) { + tempMat.set( + orig.width / trim.width, + 0, + 0, + orig.height / trim.height, + -trim.x / trim.width, + -trim.y / trim.height + ); + this.mapCoord.append(tempMat); + } + const texBase = tex.source; + const frame = this.uClampFrame; + const margin = this.clampMargin / texBase._resolution; + const offset = this.clampOffset; + frame[0] = (tex.frame.x + margin + offset) / texBase.width; + frame[1] = (tex.frame.y + margin + offset) / texBase.height; + frame[2] = (tex.frame.x + tex.frame.width - margin + offset) / texBase.width; + frame[3] = (tex.frame.y + tex.frame.height - margin + offset) / texBase.height; + this.uClampOffset[0] = offset / texBase.pixelWidth; + this.uClampOffset[1] = offset / texBase.pixelHeight; + this.isSimple = tex.frame.width === texBase.width && tex.frame.height === texBase.height && tex.rotate === 0; + return true; + } + } + + "use strict"; + class Texture extends EventEmitter { + /** + * @param {TextureOptions} param0 - Options for the texture + */ + constructor({ + source, + label, + frame, + orig, + trim, + defaultAnchor, + defaultBorders, + rotate, + dynamic + } = {}) { + var _a; + super(); + /** unique id for this texture */ + this.uid = uid("texture"); + /** A uvs object based on the given frame and the texture source */ + this.uvs = { x0: 0, y0: 0, x1: 0, y1: 0, x2: 0, y2: 0, x3: 0, y3: 0 }; + /** + * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering, + * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases) + */ + this.frame = new Rectangle(); + /** + * Does this Texture have any frame data assigned to it? + * + * This mode is enabled automatically if no frame was passed inside constructor. + * + * In this mode texture is subscribed to baseTexture events, and fires `update` on any change. + * + * Beware, after loading or resize of baseTexture event can fired two times! + * If you want more control, subscribe on baseTexture itself. + * @example + * texture.on('update', () => {}); + */ + this.noFrame = false; + /** + * Set to true if you plan on modifying the uvs of this texture. + * When this is the case, sprites and other objects using the texture will + * make sure to listen for changes to the uvs and update their vertices accordingly. + */ + this.dynamic = false; + /** is it a texture? yes! used for type checking */ + this.isTexture = true; + this.label = label; + this.source = (_a = source == null ? void 0 : source.source) != null ? _a : new TextureSource(); + this.noFrame = !frame; + if (frame) { + this.frame.copyFrom(frame); + } else { + const { width, height } = this._source; + this.frame.width = width; + this.frame.height = height; + } + this.orig = orig || this.frame; + this.trim = trim; + this.rotate = rotate != null ? rotate : 0; + this.defaultAnchor = defaultAnchor; + this.defaultBorders = defaultBorders; + this.destroyed = false; + this.dynamic = dynamic || false; + this.updateUvs(); + } + set source(value) { + if (this._source) { + this._source.off("resize", this.update, this); + } + this._source = value; + value.on("resize", this.update, this); + this.emit("update", this); + } + /** the underlying source of the texture (equivalent of baseTexture in v7) */ + get source() { + return this._source; + } + /** returns a TextureMatrix instance for this texture. By default, that object is not created because its heavy. */ + get textureMatrix() { + if (!this._textureMatrix) { + this._textureMatrix = new TextureMatrix(this); + } + return this._textureMatrix; + } + /** The width of the Texture in pixels. */ + get width() { + return this.orig.width; + } + /** The height of the Texture in pixels. */ + get height() { + return this.orig.height; + } + /** Call this function when you have modified the frame of this texture. */ + updateUvs() { + const { uvs, frame } = this; + const { width, height } = this._source; + const nX = frame.x / width; + const nY = frame.y / height; + const nW = frame.width / width; + const nH = frame.height / height; + let rotate = this.rotate; + if (rotate) { + const w2 = nW / 2; + const h2 = nH / 2; + const cX = nX + w2; + const cY = nY + h2; + rotate = groupD8.add(rotate, groupD8.NW); + uvs.x0 = cX + w2 * groupD8.uX(rotate); + uvs.y0 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + uvs.x1 = cX + w2 * groupD8.uX(rotate); + uvs.y1 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + uvs.x2 = cX + w2 * groupD8.uX(rotate); + uvs.y2 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + uvs.x3 = cX + w2 * groupD8.uX(rotate); + uvs.y3 = cY + h2 * groupD8.uY(rotate); + } else { + uvs.x0 = nX; + uvs.y0 = nY; + uvs.x1 = nX + nW; + uvs.y1 = nY; + uvs.x2 = nX + nW; + uvs.y2 = nY + nH; + uvs.x3 = nX; + uvs.y3 = nY + nH; + } + } + /** + * Destroys this texture + * @param destroySource - Destroy the source when the texture is destroyed. + */ + destroy(destroySource = false) { + if (this._source) { + if (destroySource) { + this._source.destroy(); + this._source = null; + } + } + this._textureMatrix = null; + this.destroyed = true; + this.emit("destroy", this); + this.removeAllListeners(); + } + /** call this if you have modified the `texture outside` of the constructor */ + update() { + if (this.noFrame) { + this.frame.width = this._source.width; + this.frame.height = this._source.height; + } + this.updateUvs(); + this.emit("update", this); + } + /** @deprecated since 8.0.0 */ + get baseTexture() { + deprecation(v8_0_0, "Texture.baseTexture is now Texture.source"); + return this._source; + } + } + Texture.EMPTY = new Texture({ + label: "EMPTY", + source: new TextureSource({ + label: "EMPTY" + }) + }); + Texture.EMPTY.destroy = NOOP; + Texture.WHITE = new Texture({ + source: new BufferImageSource({ + resource: new Uint8Array([255, 255, 255, 255]), + width: 1, + height: 1, + alphaMode: "premultiply-alpha-on-upload", + label: "WHITE" + }), + label: "WHITE" + }); + Texture.WHITE.destroy = NOOP; + + "use strict"; + const _Spritesheet = class _Spritesheet { + /** + * @param texture - Reference to the source BaseTexture object. + * @param {object} data - Spritesheet image data. + */ + constructor(texture, data) { + /** For multi-packed spritesheets, this contains a reference to all the other spritesheets it depends on. */ + this.linkedSheets = []; + this._texture = texture instanceof Texture ? texture : null; + this.textureSource = texture.source; + this.textures = {}; + this.animations = {}; + this.data = data; + const metaResolution = parseFloat(data.meta.scale); + if (metaResolution) { + this.resolution = metaResolution; + texture.source.resolution = this.resolution; + } else { + this.resolution = texture.source._resolution; + } + this._frames = this.data.frames; + this._frameKeys = Object.keys(this._frames); + this._batchIndex = 0; + this._callback = null; + } + /** + * Parser spritesheet from loaded data. This is done asynchronously + * to prevent creating too many Texture within a single process. + */ + parse() { + return new Promise((resolve) => { + this._callback = resolve; + this._batchIndex = 0; + if (this._frameKeys.length <= _Spritesheet.BATCH_SIZE) { + this._processFrames(0); + this._processAnimations(); + this._parseComplete(); + } else { + this._nextBatch(); + } + }); + } + /** + * Process a batch of frames + * @param initialFrameIndex - The index of frame to start. + */ + _processFrames(initialFrameIndex) { + let frameIndex = initialFrameIndex; + const maxFrames = _Spritesheet.BATCH_SIZE; + while (frameIndex - initialFrameIndex < maxFrames && frameIndex < this._frameKeys.length) { + const i = this._frameKeys[frameIndex]; + const data = this._frames[i]; + const rect = data.frame; + if (rect) { + let frame = null; + let trim = null; + const sourceSize = data.trimmed !== false && data.sourceSize ? data.sourceSize : data.frame; + const orig = new Rectangle( + 0, + 0, + Math.floor(sourceSize.w) / this.resolution, + Math.floor(sourceSize.h) / this.resolution + ); + if (data.rotated) { + frame = new Rectangle( + Math.floor(rect.x) / this.resolution, + Math.floor(rect.y) / this.resolution, + Math.floor(rect.h) / this.resolution, + Math.floor(rect.w) / this.resolution + ); + } else { + frame = new Rectangle( + Math.floor(rect.x) / this.resolution, + Math.floor(rect.y) / this.resolution, + Math.floor(rect.w) / this.resolution, + Math.floor(rect.h) / this.resolution + ); + } + if (data.trimmed !== false && data.spriteSourceSize) { + trim = new Rectangle( + Math.floor(data.spriteSourceSize.x) / this.resolution, + Math.floor(data.spriteSourceSize.y) / this.resolution, + Math.floor(rect.w) / this.resolution, + Math.floor(rect.h) / this.resolution + ); + } + this.textures[i] = new Texture({ + source: this.textureSource, + frame, + orig, + trim, + rotate: data.rotated ? 2 : 0, + defaultAnchor: data.anchor, + defaultBorders: data.borders, + label: i.toString() + }); + } + frameIndex++; + } + } + /** Parse animations config. */ + _processAnimations() { + const animations = this.data.animations || {}; + for (const animName in animations) { + this.animations[animName] = []; + for (let i = 0; i < animations[animName].length; i++) { + const frameName = animations[animName][i]; + this.animations[animName].push(this.textures[frameName]); + } + } + } + /** The parse has completed. */ + _parseComplete() { + const callback = this._callback; + this._callback = null; + this._batchIndex = 0; + callback.call(this, this.textures); + } + /** Begin the next batch of textures. */ + _nextBatch() { + this._processFrames(this._batchIndex * _Spritesheet.BATCH_SIZE); + this._batchIndex++; + setTimeout(() => { + if (this._batchIndex * _Spritesheet.BATCH_SIZE < this._frameKeys.length) { + this._nextBatch(); + } else { + this._processAnimations(); + this._parseComplete(); + } + }, 0); + } + /** + * Destroy Spritesheet and don't use after this. + * @param {boolean} [destroyBase=false] - Whether to destroy the base texture as well + */ + destroy(destroyBase = false) { + var _a; + for (const i in this.textures) { + this.textures[i].destroy(); + } + this._frames = null; + this._frameKeys = null; + this.data = null; + this.textures = null; + if (destroyBase) { + (_a = this._texture) == null ? void 0 : _a.destroy(); + this.textureSource.destroy(); + } + this._texture = null; + this.textureSource = null; + this.linkedSheets = []; + } + }; + /** The maximum number of Textures to build per process. */ + _Spritesheet.BATCH_SIZE = 1e3; + let Spritesheet = _Spritesheet; + + "use strict"; + const validImages = [ + "jpg", + "png", + "jpeg", + "avif", + "webp", + "basis", + "etc2", + "bc7", + "bc6h", + "bc5", + "bc4", + "bc3", + "bc2", + "bc1", + "eac", + "astc" + ]; + function getCacheableAssets(keys, asset, ignoreMultiPack) { + const out = {}; + keys.forEach((key) => { + out[key] = asset; + }); + Object.keys(asset.textures).forEach((key) => { + out[key] = asset.textures[key]; + }); + if (!ignoreMultiPack) { + const basePath = path.dirname(keys[0]); + asset.linkedSheets.forEach((item, i) => { + const out2 = getCacheableAssets([`${basePath}/${asset.data.meta.related_multi_packs[i]}`], item, true); + Object.assign(out, out2); + }); + } + return out; + } + const spritesheetAsset = { + extension: ExtensionType.Asset, + /** Handle the caching of the related Spritesheet Textures */ + cache: { + test: (asset) => asset instanceof Spritesheet, + getCacheableAssets: (keys, asset) => getCacheableAssets(keys, asset, false) + }, + /** Resolve the resolution of the asset. */ + resolver: { + extension: { + type: ExtensionType.ResolveParser, + name: "resolveSpritesheet" + }, + test: (value) => { + const tempURL = value.split("?")[0]; + const split = tempURL.split("."); + const extension = split.pop(); + const format = split.pop(); + return extension === "json" && validImages.includes(format); + }, + parse: (value) => { + var _a, _b; + const split = value.split("."); + return { + resolution: parseFloat((_b = (_a = Resolver.RETINA_PREFIX.exec(value)) == null ? void 0 : _a[1]) != null ? _b : "1"), + format: split[split.length - 2], + src: value + }; + } + }, + /** + * Loader plugin that parses sprite sheets! + * once the JSON has been loaded this checks to see if the JSON is spritesheet data. + * If it is, we load the spritesheets image and parse the data into Spritesheet + * All textures in the sprite sheet are then added to the cache + */ + loader: { + name: "spritesheetLoader", + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Normal, + name: "spritesheetLoader" + }, + async testParse(asset, options) { + return path.extname(options.src).toLowerCase() === ".json" && !!asset.frames; + }, + async parse(asset, options, loader) { + var _a, _b, _c; + const { + texture: imageTexture, + // if user need to use preloaded texture + imageFilename + // if user need to use custom filename (not from jsonFile.meta.image) + } = (_a = options == null ? void 0 : options.data) != null ? _a : {}; + let basePath = path.dirname(options.src); + if (basePath && basePath.lastIndexOf("/") !== basePath.length - 1) { + basePath += "/"; + } + let texture; + if (imageTexture instanceof Texture) { + texture = imageTexture; + } else { + const imagePath = copySearchParams(basePath + (imageFilename != null ? imageFilename : asset.meta.image), options.src); + const assets = await loader.load([imagePath]); + texture = assets[imagePath]; + } + const spritesheet = new Spritesheet( + texture.source, + asset + ); + await spritesheet.parse(); + const multiPacks = (_b = asset == null ? void 0 : asset.meta) == null ? void 0 : _b.related_multi_packs; + if (Array.isArray(multiPacks)) { + const promises = []; + for (const item of multiPacks) { + if (typeof item !== "string") { + continue; + } + let itemUrl = basePath + item; + if ((_c = options.data) == null ? void 0 : _c.ignoreMultiPack) { + continue; + } + itemUrl = copySearchParams(itemUrl, options.src); + promises.push(loader.load({ + src: itemUrl, + data: { + ignoreMultiPack: true + } + })); + } + const res = await Promise.all(promises); + spritesheet.linkedSheets = res; + res.forEach((item) => { + item.linkedSheets = [spritesheet].concat(spritesheet.linkedSheets.filter((sp) => sp !== item)); + }); + } + return spritesheet; + }, + async unload(spritesheet, _resolvedAsset, loader) { + await loader.unload(spritesheet.textureSource._sourceOrigin); + spritesheet.destroy(false); + } + } + }; + + "use strict"; + extensions.add(spritesheetAsset); + + "use strict"; + function updateQuadBounds(bounds, anchor, texture, padding) { + const { width, height } = texture.orig; + const trim = texture.trim; + if (trim) { + const sourceWidth = trim.width; + const sourceHeight = trim.height; + bounds.minX = trim.x - anchor._x * width - padding; + bounds.maxX = bounds.minX + sourceWidth; + bounds.minY = trim.y - anchor._y * height - padding; + bounds.maxY = bounds.minY + sourceHeight; + } else { + bounds.minX = -anchor._x * width - padding; + bounds.maxX = bounds.minX + width; + bounds.minY = -anchor._y * height - padding; + bounds.maxY = bounds.minY + height; + } + return; + } + + "use strict"; + var __defProp$W = Object.defineProperty; + var __getOwnPropSymbols$W = Object.getOwnPropertySymbols; + var __hasOwnProp$W = Object.prototype.hasOwnProperty; + var __propIsEnum$W = Object.prototype.propertyIsEnumerable; + var __defNormalProp$W = (obj, key, value) => key in obj ? __defProp$W(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$W = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$W.call(b, prop)) + __defNormalProp$W(a, prop, b[prop]); + if (__getOwnPropSymbols$W) + for (var prop of __getOwnPropSymbols$W(b)) { + if (__propIsEnum$W.call(b, prop)) + __defNormalProp$W(a, prop, b[prop]); + } + return a; + }; + var __objRest$i = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$W.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$W) + for (var prop of __getOwnPropSymbols$W(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$W.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class Sprite extends Container { + /** + * @param options - The options for creating the sprite. + */ + constructor(options = Texture.EMPTY) { + if (options instanceof Texture) { + options = { texture: options }; + } + const _a = options, { texture = Texture.EMPTY, anchor, roundPixels, width, height } = _a, rest = __objRest$i(_a, ["texture", "anchor", "roundPixels", "width", "height"]); + super(__spreadValues$W({ + label: "Sprite" + }, rest)); + this.renderPipeId = "sprite"; + this.batched = true; + this._didSpriteUpdate = false; + this._bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 }; + this._sourceBounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 }; + this._boundsDirty = true; + this._sourceBoundsDirty = true; + this._roundPixels = 0; + this._anchor = new ObservablePoint( + { + _onUpdate: () => { + this.onViewUpdate(); + } + } + ); + if (anchor) { + this.anchor = anchor; + } else if (texture.defaultAnchor) { + this.anchor = texture.defaultAnchor; + } + this.texture = texture; + this.allowChildren = false; + this.roundPixels = roundPixels != null ? roundPixels : false; + if (width) + this.width = width; + if (height) + this.height = height; + } + /** + * Helper function that creates a new sprite based on the source you provide. + * The source can be - frame id, image, video, canvas element, video element, texture + * @param source - Source to create texture from + * @param [skipCache] - Whether to skip the cache or not + * @returns The newly created sprite + */ + static from(source, skipCache = false) { + if (source instanceof Texture) { + return new Sprite(source); + } + return new Sprite(Texture.from(source, skipCache)); + } + set texture(value) { + value || (value = Texture.EMPTY); + const currentTexture = this._texture; + if (currentTexture === value) + return; + if (currentTexture && currentTexture.dynamic) + currentTexture.off("update", this.onViewUpdate, this); + if (value.dynamic) + value.on("update", this.onViewUpdate, this); + this._texture = value; + if (this._width) { + this._setWidth(this._width, this._texture.orig.width); + } + if (this._height) { + this._setHeight(this._height, this._texture.orig.height); + } + this.onViewUpdate(); + } + /** The texture that the sprite is using. */ + get texture() { + return this._texture; + } + /** + * The local bounds of the sprite. + * @type {rendering.Bounds} + */ + get bounds() { + if (this._boundsDirty) { + this._updateBounds(); + this._boundsDirty = false; + } + return this._bounds; + } + /** + * The bounds of the sprite, taking the texture's trim into account. + * @type {rendering.Bounds} + */ + get sourceBounds() { + if (this._sourceBoundsDirty) { + this._updateSourceBounds(); + this._sourceBoundsDirty = false; + } + return this._sourceBounds; + } + /** + * Checks if the object contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + const bounds = this.sourceBounds; + if (point.x >= bounds.maxX && point.x <= bounds.minX) { + if (point.y >= bounds.maxY && point.y <= bounds.minY) { + return true; + } + } + return false; + } + /** + * Adds the bounds of this object to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + const _bounds = this._texture.trim ? this.sourceBounds : this.bounds; + bounds.addFrame(_bounds.minX, _bounds.minY, _bounds.maxX, _bounds.maxY); + } + onViewUpdate() { + this._didChangeId += 1 << 12; + this._didSpriteUpdate = true; + this._sourceBoundsDirty = this._boundsDirty = true; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + _updateBounds() { + updateQuadBounds(this._bounds, this._anchor, this._texture, 0); + } + _updateSourceBounds() { + const anchor = this._anchor; + const texture = this._texture; + const sourceBounds = this._sourceBounds; + const { width, height } = texture.orig; + sourceBounds.maxX = -anchor._x * width; + sourceBounds.minX = sourceBounds.maxX + width; + sourceBounds.maxY = -anchor._y * height; + sourceBounds.minY = sourceBounds.maxY + height; + } + /** + * Destroys this sprite renderable and optionally its texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well + */ + destroy(options = false) { + super.destroy(options); + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + this._texture.destroy(destroyTextureSource); + } + this._texture = null; + this._bounds = null; + this._sourceBounds = null; + this._anchor = null; + } + /** + * The anchor sets the origin point of the sprite. The default value is taken from the {@link Texture} + * and passed to the constructor. + * + * The default is `(0,0)`, this means the sprite's origin is the top left. + * + * Setting the anchor to `(0.5,0.5)` means the sprite's origin is centered. + * + * Setting the anchor to `(1,1)` would mean the sprite's origin point will be the bottom right corner. + * + * If you pass only single parameter, it will set both x and y to the same value as shown in the example below. + * @example + * import { Sprite } from 'pixi.js'; + * + * const sprite = new Sprite({texture: Texture.WHITE}); + * sprite.anchor.set(0.5); // This will set the origin to center. (0.5) is same as (0.5, 0.5). + */ + get anchor() { + return this._anchor; + } + set anchor(value) { + typeof value === "number" ? this._anchor.set(value) : this._anchor.copyFrom(value); + } + /** + * Whether or not to round the x/y position of the sprite. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + /** The width of the sprite, setting this will actually modify the scale to achieve the value set. */ + get width() { + return Math.abs(this.scale.x) * this._texture.orig.width; + } + set width(value) { + this._setWidth(value, this._texture.orig.width); + this._width = value; + } + /** The height of the sprite, setting this will actually modify the scale to achieve the value set. */ + get height() { + return Math.abs(this.scale.y) * this._texture.orig.height; + } + set height(value) { + this._setHeight(value, this._texture.orig.height); + this._height = value; + } + /** + * Retrieves the size of the Sprite as a [Size]{@link Size} object. + * This is faster than get the width and height separately. + * @param out - Optional object to store the size in. + * @returns - The size of the Sprite. + */ + getSize(out) { + if (!out) { + out = {}; + } + out.width = Math.abs(this.scale.x) * this._texture.orig.width; + out.height = Math.abs(this.scale.y) * this._texture.orig.height; + return out; + } + /** + * Sets the size of the Sprite to the specified width and height. + * This is faster than setting the width and height separately. + * @param value - This can be either a number or a [Size]{@link Size} object. + * @param height - The height to set. Defaults to the value of `width` if not provided. + */ + setSize(value, height) { + var _a; + let convertedWidth; + let convertedHeight; + if (typeof value !== "object") { + convertedWidth = value; + convertedHeight = height != null ? height : value; + } else { + convertedWidth = value.width; + convertedHeight = (_a = value.height) != null ? _a : value.width; + } + if (convertedWidth !== void 0) { + this._setWidth(convertedWidth, this._texture.orig.width); + } + if (convertedHeight !== void 0) { + this._setHeight(convertedHeight, this._texture.orig.height); + } + } + } + + "use strict"; + const tempBounds$4 = new Bounds(); + function addMaskBounds(mask, bounds, skipUpdateTransform) { + const boundsToMask = tempBounds$4; + mask.measurable = true; + getGlobalBounds(mask, skipUpdateTransform, boundsToMask); + bounds.addBoundsMask(boundsToMask); + mask.measurable = false; + } + + "use strict"; + function addMaskLocalBounds(mask, bounds, localRoot) { + const boundsToMask = boundsPool.get(); + mask.measurable = true; + const tempMatrix = matrixPool.get().identity(); + const relativeMask = getMatrixRelativeToParent(mask, localRoot, tempMatrix); + getLocalBounds(mask, boundsToMask, relativeMask); + mask.measurable = false; + bounds.addBoundsMask(boundsToMask); + matrixPool.return(tempMatrix); + boundsPool.return(boundsToMask); + } + function getMatrixRelativeToParent(target, root, matrix) { + if (!target) { + warn("Mask bounds, renderable is not inside the root container"); + return matrix; + } + if (target !== root) { + getMatrixRelativeToParent(target.parent, root, matrix); + target.updateLocalTransform(); + matrix.append(target.localTransform); + } + return matrix; + } + + "use strict"; + class AlphaMask { + constructor(options) { + this.priority = 0; + this.pipe = "alphaMask"; + if (options == null ? void 0 : options.mask) { + this.init(options.mask); + } + } + init(mask) { + this.mask = mask; + this.renderMaskToTexture = !(mask instanceof Sprite); + this.mask.renderable = this.renderMaskToTexture; + this.mask.includeInBuild = !this.renderMaskToTexture; + this.mask.measurable = false; + } + reset() { + this.mask.measurable = true; + this.mask = null; + } + addBounds(bounds, skipUpdateTransform) { + addMaskBounds(this.mask, bounds, skipUpdateTransform); + } + addLocalBounds(bounds, localRoot) { + addMaskLocalBounds(this.mask, bounds, localRoot); + } + containsPoint(point, hitTestFn) { + const mask = this.mask; + return hitTestFn(mask, point); + } + destroy() { + this.reset(); + } + static test(mask) { + return mask instanceof Sprite; + } + } + AlphaMask.extension = ExtensionType.MaskEffect; + + "use strict"; + class ColorMask { + constructor(options) { + this.priority = 0; + this.pipe = "colorMask"; + if (options == null ? void 0 : options.mask) { + this.init(options.mask); + } + } + init(mask) { + this.mask = mask; + } + destroy() { + } + static test(mask) { + return typeof mask === "number"; + } + } + ColorMask.extension = ExtensionType.MaskEffect; + + "use strict"; + class StencilMask { + constructor(options) { + this.priority = 0; + this.pipe = "stencilMask"; + if (options == null ? void 0 : options.mask) { + this.init(options.mask); + } + } + init(mask) { + this.mask = mask; + this.mask.includeInBuild = false; + this.mask.measurable = false; + } + reset() { + this.mask.measurable = true; + this.mask.includeInBuild = true; + this.mask = null; + } + addBounds(bounds, skipUpdateTransform) { + addMaskBounds(this.mask, bounds, skipUpdateTransform); + } + addLocalBounds(bounds, localRoot) { + addMaskLocalBounds(this.mask, bounds, localRoot); + } + containsPoint(point, hitTestFn) { + const mask = this.mask; + return hitTestFn(mask, point); + } + destroy() { + this.reset(); + } + static test(mask) { + return mask instanceof Container; + } + } + StencilMask.extension = ExtensionType.MaskEffect; + + "use strict"; + class CanvasSource extends TextureSource { + constructor(options) { + if (!options.resource) { + options.resource = DOMAdapter.get().createCanvas(); + } + if (!options.width) { + options.width = options.resource.width; + if (!options.autoDensity) { + options.width /= options.resolution; + } + } + if (!options.height) { + options.height = options.resource.height; + if (!options.autoDensity) { + options.height /= options.resolution; + } + } + super(options); + this.uploadMethodId = "image"; + this.autoDensity = options.autoDensity; + const canvas = options.resource; + if (this.pixelWidth !== canvas.width || this.pixelWidth !== canvas.height) { + this.resizeCanvas(); + } + this.transparent = !!options.transparent; + } + resizeCanvas() { + if (this.autoDensity) { + this.resource.style.width = `${this.width}px`; + this.resource.style.height = `${this.height}px`; + } + if (this.resource.width !== this.pixelWidth || this.resource.height !== this.pixelHeight) { + this.resource.width = this.pixelWidth; + this.resource.height = this.pixelHeight; + } + } + resize(width = this.width, height = this.height, resolution = this._resolution) { + const didResize = super.resize(width, height, resolution); + if (didResize) { + this.resizeCanvas(); + } + return didResize; + } + static test(resource) { + return globalThis.HTMLCanvasElement && resource instanceof HTMLCanvasElement || globalThis.OffscreenCanvas && resource instanceof OffscreenCanvas; + } + } + CanvasSource.extension = ExtensionType.TextureSource; + + "use strict"; + class ImageSource extends TextureSource { + constructor(options) { + if (options.resource && (globalThis.HTMLImageElement && options.resource instanceof HTMLImageElement)) { + const canvas = DOMAdapter.get().createCanvas(options.resource.width, options.resource.height); + const context = canvas.getContext("2d"); + context.drawImage(options.resource, 0, 0); + options.resource = canvas; + warn("ImageSource: Image element passed, converting to canvas. Use CanvasSource instead."); + } + super(options); + this.uploadMethodId = "image"; + this.autoGarbageCollect = true; + } + static test(resource) { + return globalThis.HTMLImageElement && resource instanceof HTMLImageElement || typeof ImageBitmap !== "undefined" && resource instanceof ImageBitmap; + } + } + ImageSource.extension = ExtensionType.TextureSource; + + "use strict"; + let promise; + async function detectVideoAlphaMode() { + promise != null ? promise : promise = (async () => { + var _a; + const canvas = document.createElement("canvas"); + const gl = canvas.getContext("webgl"); + if (!gl) { + return "premultiply-alpha-on-upload"; + } + const video = await new Promise((resolve) => { + const video2 = document.createElement("video"); + video2.onloadeddata = () => resolve(video2); + video2.onerror = () => resolve(null); + video2.autoplay = false; + video2.crossOrigin = "anonymous"; + video2.preload = "auto"; + video2.src = "data:video/webm;base64,GkXfo59ChoEBQveBAULygQRC84EIQoKEd2VibUKHgQJChYECGFOAZwEAAAAAAAHTEU2bdLpNu4tTq4QVSalmU6yBoU27i1OrhBZUrmtTrIHGTbuMU6uEElTDZ1OsggEXTbuMU6uEHFO7a1OsggG97AEAAAAAAABZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVSalmoCrXsYMPQkBNgIRMYXZmV0GETGF2ZkSJiEBEAAAAAAAAFlSua8yuAQAAAAAAAEPXgQFzxYgAAAAAAAAAAZyBACK1nIN1bmSIgQCGhVZfVlA5g4EBI+ODhAJiWgDglLCBArqBApqBAlPAgQFVsIRVuYEBElTDZ9Vzc9JjwItjxYgAAAAAAAAAAWfInEWjh0VOQ09ERVJEh49MYXZjIGxpYnZweC12cDlnyKJFo4hEVVJBVElPTkSHlDAwOjAwOjAwLjA0MDAwMDAwMAAAH0O2dcfngQCgwqGggQAAAIJJg0IAABAAFgA4JBwYSgAAICAAEb///4r+AAB1oZ2mm+6BAaWWgkmDQgAAEAAWADgkHBhKAAAgIABIQBxTu2uRu4+zgQC3iveBAfGCAXHwgQM="; + video2.load(); + }); + if (!video) { + return "premultiply-alpha-on-upload"; + } + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + const framebuffer = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); + gl.framebufferTexture2D( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0, + gl.TEXTURE_2D, + texture, + 0 + ); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video); + const pixel = new Uint8Array(4); + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); + gl.deleteFramebuffer(framebuffer); + gl.deleteTexture(texture); + (_a = gl.getExtension("WEBGL_lose_context")) == null ? void 0 : _a.loseContext(); + return pixel[0] <= pixel[3] ? "premultiplied-alpha" : "premultiply-alpha-on-upload"; + })(); + return promise; + } + + "use strict"; + var __defProp$V = Object.defineProperty; + var __defProps$l = Object.defineProperties; + var __getOwnPropDescs$l = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$V = Object.getOwnPropertySymbols; + var __hasOwnProp$V = Object.prototype.hasOwnProperty; + var __propIsEnum$V = Object.prototype.propertyIsEnumerable; + var __defNormalProp$V = (obj, key, value) => key in obj ? __defProp$V(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$V = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$V.call(b, prop)) + __defNormalProp$V(a, prop, b[prop]); + if (__getOwnPropSymbols$V) + for (var prop of __getOwnPropSymbols$V(b)) { + if (__propIsEnum$V.call(b, prop)) + __defNormalProp$V(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$l = (a, b) => __defProps$l(a, __getOwnPropDescs$l(b)); + const _VideoSource = class _VideoSource extends TextureSource { + constructor(options) { + var _a; + super(options); + // Public + /** Whether or not the video is ready to play. */ + this.isReady = false; + /** The upload method for this texture. */ + this.uploadMethodId = "video"; + options = __spreadValues$V(__spreadValues$V({}, _VideoSource.defaultOptions), options); + this._autoUpdate = true; + this._isConnectedToTicker = false; + this._updateFPS = options.updateFPS || 0; + this._msToNextUpdate = 0; + this.autoPlay = options.autoPlay !== false; + this.alphaMode = (_a = options.alphaMode) != null ? _a : "premultiply-alpha-on-upload"; + this._videoFrameRequestCallback = this._videoFrameRequestCallback.bind(this); + this._videoFrameRequestCallbackHandle = null; + this._load = null; + this._resolve = null; + this._reject = null; + this._onCanPlay = this._onCanPlay.bind(this); + this._onCanPlayThrough = this._onCanPlayThrough.bind(this); + this._onError = this._onError.bind(this); + this._onPlayStart = this._onPlayStart.bind(this); + this._onPlayStop = this._onPlayStop.bind(this); + this._onSeeked = this._onSeeked.bind(this); + if (options.autoLoad !== false) { + void this.load(); + } + } + /** Update the video frame if the source is not destroyed and meets certain conditions. */ + updateFrame() { + if (this.destroyed) { + return; + } + if (this._updateFPS) { + const elapsedMS = Ticker.shared.elapsedMS * this.resource.playbackRate; + this._msToNextUpdate = Math.floor(this._msToNextUpdate - elapsedMS); + } + if (!this._updateFPS || this._msToNextUpdate <= 0) { + this._msToNextUpdate = this._updateFPS ? Math.floor(1e3 / this._updateFPS) : 0; + } + if (this.isValid) { + this.update(); + } + } + /** Callback to update the video frame and potentially request the next frame update. */ + _videoFrameRequestCallback() { + this.updateFrame(); + if (this.destroyed) { + this._videoFrameRequestCallbackHandle = null; + } else { + this._videoFrameRequestCallbackHandle = this.resource.requestVideoFrameCallback( + this._videoFrameRequestCallback + ); + } + } + /** + * Checks if the resource has valid dimensions. + * @returns {boolean} True if width and height are set, otherwise false. + */ + get isValid() { + return !!this.resource.videoWidth && !!this.resource.videoHeight; + } + /** + * Start preloading the video resource. + * @returns {Promise} Handle the validate event + */ + async load() { + if (this._load) { + return this._load; + } + const source = this.resource; + const options = this.options; + if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA) && source.width && source.height) { + source.complete = true; + } + source.addEventListener("play", this._onPlayStart); + source.addEventListener("pause", this._onPlayStop); + source.addEventListener("seeked", this._onSeeked); + if (!this._isSourceReady()) { + if (!options.preload) { + source.addEventListener("canplay", this._onCanPlay); + } + source.addEventListener("canplaythrough", this._onCanPlayThrough); + source.addEventListener("error", this._onError, true); + } else { + this._mediaReady(); + } + this.alphaMode = await detectVideoAlphaMode(); + this._load = new Promise((resolve, reject) => { + if (this.isValid) { + resolve(this); + } else { + this._resolve = resolve; + this._reject = reject; + if (options.preloadTimeoutMs !== void 0) { + this._preloadTimeout = setTimeout(() => { + this._onError(new ErrorEvent(`Preload exceeded timeout of ${options.preloadTimeoutMs}ms`)); + }); + } + source.load(); + } + }); + return this._load; + } + /** + * Handle video error events. + * @param event - The error event + */ + _onError(event) { + this.resource.removeEventListener("error", this._onError, true); + this.emit("error", event); + if (this._reject) { + this._reject(event); + this._reject = null; + this._resolve = null; + } + } + /** + * Checks if the underlying source is playing. + * @returns True if playing. + */ + _isSourcePlaying() { + const source = this.resource; + return !source.paused && !source.ended; + } + /** + * Checks if the underlying source is ready for playing. + * @returns True if ready. + */ + _isSourceReady() { + const source = this.resource; + return source.readyState > 2; + } + /** Runs the update loop when the video is ready to play. */ + _onPlayStart() { + if (!this.isValid) { + this._mediaReady(); + } + this._configureAutoUpdate(); + } + /** Stops the update loop when a pause event is triggered. */ + _onPlayStop() { + this._configureAutoUpdate(); + } + /** Handles behavior when the video completes seeking to the current playback position. */ + _onSeeked() { + if (this._autoUpdate && !this._isSourcePlaying()) { + this._msToNextUpdate = 0; + this.updateFrame(); + this._msToNextUpdate = 0; + } + } + _onCanPlay() { + const source = this.resource; + source.removeEventListener("canplay", this._onCanPlay); + this._mediaReady(); + } + _onCanPlayThrough() { + const source = this.resource; + source.removeEventListener("canplaythrough", this._onCanPlay); + if (this._preloadTimeout) { + clearTimeout(this._preloadTimeout); + this._preloadTimeout = void 0; + } + this._mediaReady(); + } + /** Fired when the video is loaded and ready to play. */ + _mediaReady() { + const source = this.resource; + if (this.isValid) { + this.isReady = true; + this.resize(source.videoWidth, source.videoHeight); + } + this._msToNextUpdate = 0; + this.updateFrame(); + this._msToNextUpdate = 0; + if (this._resolve) { + this._resolve(this); + this._resolve = null; + this._reject = null; + } + if (this._isSourcePlaying()) { + this._onPlayStart(); + } else if (this.autoPlay) { + void this.resource.play(); + } + } + /** Cleans up resources and event listeners associated with this texture. */ + destroy() { + this._configureAutoUpdate(); + const source = this.resource; + if (source) { + source.removeEventListener("play", this._onPlayStart); + source.removeEventListener("pause", this._onPlayStop); + source.removeEventListener("seeked", this._onSeeked); + source.removeEventListener("canplay", this._onCanPlay); + source.removeEventListener("canplaythrough", this._onCanPlayThrough); + source.removeEventListener("error", this._onError, true); + source.pause(); + source.src = ""; + source.load(); + } + super.destroy(); + } + /** Should the base texture automatically update itself, set to true by default. */ + get autoUpdate() { + return this._autoUpdate; + } + set autoUpdate(value) { + if (value !== this._autoUpdate) { + this._autoUpdate = value; + this._configureAutoUpdate(); + } + } + /** + * How many times a second to update the texture from the video. + * Leave at 0 to update at every render. + * A lower fps can help performance, as updating the texture at 60fps on a 30ps video may not be efficient. + */ + get updateFPS() { + return this._updateFPS; + } + set updateFPS(value) { + if (value !== this._updateFPS) { + this._updateFPS = value; + this._configureAutoUpdate(); + } + } + /** + * Configures the updating mechanism based on the current state and settings. + * + * This method decides between using the browser's native video frame callback or a custom ticker + * for updating the video frame. It ensures optimal performance and responsiveness + * based on the video's state, playback status, and the desired frames-per-second setting. + * + * - If `_autoUpdate` is enabled and the video source is playing: + * - It will prefer the native video frame callback if available and no specific FPS is set. + * - Otherwise, it will use a custom ticker for manual updates. + * - If `_autoUpdate` is disabled or the video isn't playing, any active update mechanisms are halted. + */ + _configureAutoUpdate() { + if (this._autoUpdate && this._isSourcePlaying()) { + if (!this._updateFPS && this.resource.requestVideoFrameCallback) { + if (this._isConnectedToTicker) { + Ticker.shared.remove(this.updateFrame, this); + this._isConnectedToTicker = false; + this._msToNextUpdate = 0; + } + if (this._videoFrameRequestCallbackHandle === null) { + this._videoFrameRequestCallbackHandle = this.resource.requestVideoFrameCallback( + this._videoFrameRequestCallback + ); + } + } else { + if (this._videoFrameRequestCallbackHandle !== null) { + this.resource.cancelVideoFrameCallback(this._videoFrameRequestCallbackHandle); + this._videoFrameRequestCallbackHandle = null; + } + if (!this._isConnectedToTicker) { + Ticker.shared.add(this.updateFrame, this); + this._isConnectedToTicker = true; + this._msToNextUpdate = 0; + } + } + } else { + if (this._videoFrameRequestCallbackHandle !== null) { + this.resource.cancelVideoFrameCallback(this._videoFrameRequestCallbackHandle); + this._videoFrameRequestCallbackHandle = null; + } + if (this._isConnectedToTicker) { + Ticker.shared.remove(this.updateFrame, this); + this._isConnectedToTicker = false; + this._msToNextUpdate = 0; + } + } + } + static test(resource) { + return globalThis.HTMLVideoElement && resource instanceof HTMLVideoElement || globalThis.VideoFrame && resource instanceof VideoFrame; + } + }; + _VideoSource.extension = ExtensionType.TextureSource; + /** The default options for video sources. */ + _VideoSource.defaultOptions = __spreadProps$l(__spreadValues$V({}, TextureSource.defaultOptions), { + /** If true, the video will start loading immediately. */ + autoLoad: true, + /** If true, the video will start playing as soon as it is loaded. */ + autoPlay: true, + /** The number of times a second to update the texture from the video. Leave at 0 to update at every render. */ + updateFPS: 0, + /** If true, the video will be loaded with the `crossorigin` attribute. */ + crossorigin: true, + /** If true, the video will loop when it ends. */ + loop: false, + /** If true, the video will be muted. */ + muted: true, + /** If true, the video will play inline. */ + playsinline: true, + /** If true, the video will be preloaded. */ + preload: false + }); + /** + * Map of video MIME types that can't be directly derived from file extensions. + * @readonly + */ + _VideoSource.MIME_TYPES = { + ogv: "video/ogg", + mov: "video/quicktime", + m4v: "video/mp4" + }; + let VideoSource = _VideoSource; + + "use strict"; + class CacheClass { + constructor() { + this._parsers = []; + this._cache = /* @__PURE__ */ new Map(); + this._cacheMap = /* @__PURE__ */ new Map(); + } + /** Clear all entries. */ + reset() { + this._cacheMap.clear(); + this._cache.clear(); + } + /** + * Check if the key exists + * @param key - The key to check + */ + has(key) { + return this._cache.has(key); + } + /** + * Fetch entry by key + * @param key - The key of the entry to get + */ + get(key) { + const result = this._cache.get(key); + if (!result) { + warn(`[Assets] Asset id ${key} was not found in the Cache`); + } + return result; + } + /** + * Set a value by key or keys name + * @param key - The key or keys to set + * @param value - The value to store in the cache or from which cacheable assets will be derived. + */ + set(key, value) { + const keys = convertToList(key); + let cacheableAssets; + for (let i = 0; i < this.parsers.length; i++) { + const parser = this.parsers[i]; + if (parser.test(value)) { + cacheableAssets = parser.getCacheableAssets(keys, value); + break; + } + } + const cacheableMap = new Map(Object.entries(cacheableAssets || {})); + if (!cacheableAssets) { + keys.forEach((key2) => { + cacheableMap.set(key2, value); + }); + } + const cacheKeys = [...cacheableMap.keys()]; + const cachedAssets = { + cacheKeys, + keys + }; + keys.forEach((key2) => { + this._cacheMap.set(key2, cachedAssets); + }); + cacheKeys.forEach((key2) => { + const val = cacheableAssets ? cacheableAssets[key2] : value; + if (this._cache.has(key2) && this._cache.get(key2) !== val) { + warn("[Cache] already has key:", key2); + } + this._cache.set(key2, cacheableMap.get(key2)); + }); + } + /** + * Remove entry by key + * + * This function will also remove any associated alias from the cache also. + * @param key - The key of the entry to remove + */ + remove(key) { + if (!this._cacheMap.has(key)) { + warn(`[Assets] Asset id ${key} was not found in the Cache`); + return; + } + const cacheMap = this._cacheMap.get(key); + const cacheKeys = cacheMap.cacheKeys; + cacheKeys.forEach((key2) => { + this._cache.delete(key2); + }); + cacheMap.keys.forEach((key2) => { + this._cacheMap.delete(key2); + }); + } + /** All loader parsers registered */ + get parsers() { + return this._parsers; + } + } + const Cache = new CacheClass(); + + "use strict"; + const sources = []; + extensions.handleByList(ExtensionType.TextureSource, sources); + function autoDetectSource(options = {}) { + const hasResource = options && options.resource; + const res = hasResource ? options.resource : options; + const opts = hasResource ? options : { resource: options }; + for (let i = 0; i < sources.length; i++) { + const Source = sources[i]; + if (Source.test(res)) { + return new Source(opts); + } + } + throw new Error(`Could not find a source type for resource: ${opts.resource}`); + } + function resourceToTexture(options = {}, skipCache = false) { + const hasResource = options && options.resource; + const resource = hasResource ? options.resource : options; + const opts = hasResource ? options : { resource: options }; + if (!skipCache && Cache.has(resource)) { + return Cache.get(resource); + } + const texture = new Texture({ source: autoDetectSource(opts) }); + texture.on("destroy", () => { + if (Cache.has(resource)) { + Cache.remove(resource); + } + }); + if (!skipCache) { + Cache.set(resource, texture); + } + return texture; + } + function textureFrom(id, skipCache = false) { + if (typeof id === "string") { + return Cache.get(id); + } else if (id instanceof TextureSource) { + return new Texture({ source: id }); + } + return resourceToTexture(id, skipCache); + } + Texture.from = textureFrom; + + "use strict"; + extensions.add(AlphaMask, ColorMask, StencilMask, VideoSource, ImageSource, CanvasSource, BufferImageSource); + + "use strict"; + var BufferUsage = /* @__PURE__ */ ((BufferUsage2) => { + BufferUsage2[BufferUsage2["MAP_READ"] = 1] = "MAP_READ"; + BufferUsage2[BufferUsage2["MAP_WRITE"] = 2] = "MAP_WRITE"; + BufferUsage2[BufferUsage2["COPY_SRC"] = 4] = "COPY_SRC"; + BufferUsage2[BufferUsage2["COPY_DST"] = 8] = "COPY_DST"; + BufferUsage2[BufferUsage2["INDEX"] = 16] = "INDEX"; + BufferUsage2[BufferUsage2["VERTEX"] = 32] = "VERTEX"; + BufferUsage2[BufferUsage2["UNIFORM"] = 64] = "UNIFORM"; + BufferUsage2[BufferUsage2["STORAGE"] = 128] = "STORAGE"; + BufferUsage2[BufferUsage2["INDIRECT"] = 256] = "INDIRECT"; + BufferUsage2[BufferUsage2["QUERY_RESOLVE"] = 512] = "QUERY_RESOLVE"; + BufferUsage2[BufferUsage2["STATIC"] = 1024] = "STATIC"; + return BufferUsage2; + })(BufferUsage || {}); + + "use strict"; + class Buffer extends EventEmitter { + /** + * Creates a new Buffer with the given options + * @param options - the options for the buffer + */ + constructor(options) { + let { data, size } = options; + const { usage, label, shrinkToFit } = options; + super(); + /** + * emits when the underlying buffer has changed shape (i.e. resized) + * letting the renderer know that it needs to discard the old buffer on the GPU and create a new one + * @event change + */ + /** + * emits when the underlying buffer data has been updated. letting the renderer know + * that it needs to update the buffer on the GPU + * @event update + */ + /** + * emits when the buffer is destroyed. letting the renderer know that it needs to destroy the buffer on the GPU + * @event destroy + */ + /** + * a unique id for this uniform group used through the renderer + * @internal + * @ignore + */ + this.uid = uid("buffer"); + /** + * a resource type, used to identify how to handle it when its in a bind group / shader resource + * @internal + * @ignore + */ + this._resourceType = "buffer"; + /** + * the resource id used internally by the renderer to build bind group keys + * @internal + * @ignore + */ + this._resourceId = uid("resource"); + /** + * used internally to know if a uniform group was used in the last render pass + * @internal + * @ignore + */ + this._touched = 0; + /** + * @internal + * @ignore + */ + this._updateID = 1; + /** + * should the GPU buffer be shrunk when the data becomes smaller? + * changing this will cause the buffer to be destroyed and a new one created on the GPU + * this can be expensive, especially if the buffer is already big enough! + * setting this to false will prevent the buffer from being shrunk. This will yield better performance + * if you are constantly setting data that is changing size often. + * @default true + */ + this.shrinkToFit = true; + /** + * Has the buffer been destroyed? + * @readonly + */ + this.destroyed = false; + if (data instanceof Array) { + data = new Float32Array(data); + } + this._data = data; + size = size != null ? size : data == null ? void 0 : data.byteLength; + const mappedAtCreation = !!data; + this.descriptor = { + size, + usage, + mappedAtCreation, + label + }; + this.shrinkToFit = shrinkToFit != null ? shrinkToFit : true; + } + /** the data in the buffer */ + get data() { + return this._data; + } + set data(value) { + this.setDataWithSize(value, value.length, true); + } + /** whether the buffer is static or not */ + get static() { + return !!(this.descriptor.usage & BufferUsage.STATIC); + } + set static(value) { + if (value) { + this.descriptor.usage |= BufferUsage.STATIC; + } else { + this.descriptor.usage &= ~BufferUsage.STATIC; + } + } + /** + * Sets the data in the buffer to the given value. This will immediately update the buffer on the GPU. + * If you only want to update a subset of the buffer, you can pass in the size of the data. + * @param value - the data to set + * @param size - the size of the data in bytes + * @param syncGPU - should the buffer be updated on the GPU immediately? + */ + setDataWithSize(value, size, syncGPU) { + this._updateID++; + this._updateSize = size * value.BYTES_PER_ELEMENT; + if (this._data === value) { + if (syncGPU) + this.emit("update", this); + return; + } + const oldData = this._data; + this._data = value; + if (oldData.length !== value.length) { + if (!this.shrinkToFit && value.byteLength < oldData.byteLength) { + if (syncGPU) + this.emit("update", this); + } else { + this.descriptor.size = value.byteLength; + this._resourceId = uid("resource"); + this.emit("change", this); + } + return; + } + if (syncGPU) + this.emit("update", this); + } + /** + * updates the buffer on the GPU to reflect the data in the buffer. + * By default it will update the entire buffer. If you only want to update a subset of the buffer, + * you can pass in the size of the buffer to update. + * @param sizeInBytes - the new size of the buffer in bytes + */ + update(sizeInBytes) { + this._updateSize = sizeInBytes != null ? sizeInBytes : this._updateSize; + this._updateID++; + this.emit("update", this); + } + /** Destroys the buffer */ + destroy() { + this.destroyed = true; + this.emit("destroy", this); + this.emit("change", this); + this._data = null; + this.descriptor = null; + this.removeAllListeners(); + } + } + + "use strict"; + function ensureIsBuffer(buffer, index) { + if (!(buffer instanceof Buffer)) { + let usage = index ? BufferUsage.INDEX : BufferUsage.VERTEX; + if (buffer instanceof Array) { + if (index) { + buffer = new Uint32Array(buffer); + usage = BufferUsage.INDEX | BufferUsage.COPY_DST; + } else { + buffer = new Float32Array(buffer); + usage = BufferUsage.VERTEX | BufferUsage.COPY_DST; + } + } + buffer = new Buffer({ + data: buffer, + label: index ? "index-mesh-buffer" : "vertex-mesh-buffer", + usage + }); + } + return buffer; + } + + "use strict"; + function getGeometryBounds(geometry, attributeId, bounds) { + const attribute = geometry.getAttribute(attributeId); + if (!attribute) { + bounds.minX = 0; + bounds.minY = 0; + bounds.maxX = 0; + bounds.maxY = 0; + return bounds; + } + const data = attribute.buffer.data; + let minX = Infinity; + let minY = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + const byteSize = data.BYTES_PER_ELEMENT; + const offset = (attribute.offset || 0) / byteSize; + const stride = (attribute.stride || 2 * 4) / byteSize; + for (let i = offset; i < data.length; i += stride) { + const x = data[i]; + const y = data[i + 1]; + if (x > maxX) + maxX = x; + if (y > maxY) + maxY = y; + if (x < minX) + minX = x; + if (y < minY) + minY = y; + } + bounds.minX = minX; + bounds.minY = minY; + bounds.maxX = maxX; + bounds.maxY = maxY; + return bounds; + } + + "use strict"; + function ensureIsAttribute(attribute) { + if (attribute instanceof Buffer || Array.isArray(attribute) || attribute.BYTES_PER_ELEMENT) { + attribute = { + buffer: attribute + }; + } + attribute.buffer = ensureIsBuffer(attribute.buffer, false); + return attribute; + } + class Geometry extends EventEmitter { + /** + * Create a new instance of a geometry + * @param options - The options for the geometry. + */ + constructor(options) { + const { attributes, indexBuffer, topology } = options; + super(); + /** The unique id of the geometry. */ + this.uid = uid("geometry"); + /** + * the layout key will be generated by WebGPU all geometries that have the same structure + * will have the same layout key. This is used to cache the pipeline layout + * @internal + * @ignore + */ + this._layoutKey = 0; + /** the instance count of the geometry to draw */ + this.instanceCount = 1; + this._bounds = new Bounds(); + this._boundsDirty = true; + this.attributes = attributes; + this.buffers = []; + this.instanceCount = options.instanceCount || 1; + for (const i in attributes) { + const attribute = attributes[i] = ensureIsAttribute(attributes[i]); + const bufferIndex = this.buffers.indexOf(attribute.buffer); + if (bufferIndex === -1) { + this.buffers.push(attribute.buffer); + attribute.buffer.on("update", this.onBufferUpdate, this); + attribute.buffer.on("change", this.onBufferUpdate, this); + } + } + if (indexBuffer) { + this.indexBuffer = ensureIsBuffer(indexBuffer, true); + this.buffers.push(this.indexBuffer); + } + this.topology = topology || "triangle-list"; + } + onBufferUpdate() { + this._boundsDirty = true; + this.emit("update", this); + } + /** + * Returns the requested attribute. + * @param id - The name of the attribute required + * @returns - The attribute requested. + */ + getAttribute(id) { + return this.attributes[id]; + } + /** + * Returns the index buffer + * @returns - The index buffer. + */ + getIndex() { + return this.indexBuffer; + } + /** + * Returns the requested buffer. + * @param id - The name of the buffer required. + * @returns - The buffer requested. + */ + getBuffer(id) { + return this.getAttribute(id).buffer; + } + /** + * Used to figure out how many vertices there are in this geometry + * @returns the number of vertices in the geometry + */ + getSize() { + for (const i in this.attributes) { + const attribute = this.attributes[i]; + const buffer = attribute.buffer; + return buffer.data.length / (attribute.stride / 4 || attribute.size); + } + return 0; + } + /** Returns the bounds of the geometry. */ + get bounds() { + if (!this._boundsDirty) + return this._bounds; + this._boundsDirty = false; + return getGeometryBounds(this, "aPosition", this._bounds); + } + /** + * destroys the geometry. + * @param destroyBuffers - destroy the buffers associated with this geometry + */ + destroy(destroyBuffers = false) { + this.emit("destroy", this); + this.removeAllListeners(); + if (destroyBuffers) { + this.buffers.forEach((buffer) => buffer.destroy()); + } + this.attributes = null; + this.buffers = null; + this.indexBuffer = null; + this._bounds = null; + } + } + + "use strict"; + const placeHolderBufferData = new Float32Array(1); + const placeHolderIndexData = new Uint32Array(1); + class BatchGeometry extends Geometry { + constructor() { + const vertexSize = 6; + const attributeBuffer = new Buffer({ + data: placeHolderBufferData, + label: "attribute-batch-buffer", + usage: BufferUsage.VERTEX | BufferUsage.COPY_DST, + shrinkToFit: false + }); + const indexBuffer = new Buffer({ + data: placeHolderIndexData, + label: "index-batch-buffer", + usage: BufferUsage.INDEX | BufferUsage.COPY_DST, + // | BufferUsage.STATIC, + shrinkToFit: false + }); + const stride = vertexSize * 4; + super({ + attributes: { + aPosition: { + buffer: attributeBuffer, + format: "float32x2", + stride, + offset: 0, + location: 1 + }, + aUV: { + buffer: attributeBuffer, + format: "float32x2", + stride, + offset: 2 * 4, + location: 3 + }, + aColor: { + buffer: attributeBuffer, + format: "unorm8x4", + stride, + offset: 4 * 4, + location: 0 + }, + aTextureIdAndRound: { + buffer: attributeBuffer, + format: "uint16x2", + stride, + offset: 5 * 4, + location: 2 + } + }, + indexBuffer + }); + } + } + + "use strict"; + class BindGroup { + /** + * Create a new instance eof the Bind Group. + * @param resources - The resources that are bound together for use by a shader. + */ + constructor(resources) { + /** The resources that are bound together for use by a shader. */ + this.resources = /* @__PURE__ */ Object.create(null); + this._dirty = true; + let index = 0; + for (const i in resources) { + const resource = resources[i]; + this.setResource(resource, index++); + } + this._updateKey(); + } + /** + * Updates the key if its flagged as dirty. This is used internally to + * match this bind group to a WebGPU BindGroup. + * @internal + * @ignore + */ + _updateKey() { + if (!this._dirty) + return; + this._dirty = false; + const keyParts = []; + let index = 0; + for (const i in this.resources) { + keyParts[index++] = this.resources[i]._resourceId; + } + this._key = keyParts.join("|"); + } + /** + * Set a resource at a given index. this function will + * ensure that listeners will be removed from the current resource + * and added to the new resource. + * @param resource - The resource to set. + * @param index - The index to set the resource at. + */ + setResource(resource, index) { + var _a, _b; + const currentResource = this.resources[index]; + if (resource === currentResource) + return; + if (currentResource) { + (_a = resource.off) == null ? void 0 : _a.call(resource, "change", this.onResourceChange, this); + } + (_b = resource.on) == null ? void 0 : _b.call(resource, "change", this.onResourceChange, this); + this.resources[index] = resource; + this._dirty = true; + } + /** + * Returns the resource at the current specified index. + * @param index - The index of the resource to get. + * @returns - The resource at the specified index. + */ + getResource(index) { + return this.resources[index]; + } + /** + * Used internally to 'touch' each resource, to ensure that the GC + * knows that all resources in this bind group are still being used. + * @param tick - The current tick. + * @internal + * @ignore + */ + _touch(tick) { + const resources = this.resources; + for (const i in resources) { + resources[i]._touched = tick; + } + } + /** Destroys this bind group and removes all listeners. */ + destroy() { + var _a; + const resources = this.resources; + for (const i in resources) { + const resource = resources[i]; + (_a = resource.off) == null ? void 0 : _a.call(resource, "change", this.onResourceChange, this); + } + this.resources = null; + } + onResourceChange(resource) { + this._dirty = true; + if (resource.destroyed) { + const resources = this.resources; + for (const i in resources) { + if (resources[i] === resource) { + resources[i] = null; + } + } + } else { + this._updateKey(); + } + } + } + + "use strict"; + let context; + function getTestContext() { + if (!context || (context == null ? void 0 : context.isContextLost())) { + const canvas = DOMAdapter.get().createCanvas(); + context = canvas.getContext("webgl", {}); + } + return context; + } + + "use strict"; + let maxRecommendedTexturesCache = null; + function maxRecommendedTextures() { + if (maxRecommendedTexturesCache) + return maxRecommendedTexturesCache; + const gl = getTestContext(); + maxRecommendedTexturesCache = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); + return maxRecommendedTexturesCache; + } + + "use strict"; + const cachedGroups = {}; + function getTextureBatchBindGroup(textures, size) { + let uid = 0; + for (let i = 0; i < size; i++) { + uid = uid * 31 + textures[i].uid >>> 0; + } + return cachedGroups[uid] || generateTextureBatchBindGroup(textures, uid); + } + let maxTextures = 0; + function generateTextureBatchBindGroup(textures, key) { + const bindGroupResources = {}; + let bindIndex = 0; + if (!maxTextures) + maxTextures = maxRecommendedTextures(); + for (let i = 0; i < maxTextures; i++) { + const texture = i < textures.length ? textures[i] : Texture.EMPTY.source; + bindGroupResources[bindIndex++] = texture.source; + bindGroupResources[bindIndex++] = texture.style; + } + const bindGroup = new BindGroup(bindGroupResources); + cachedGroups[key] = bindGroup; + return bindGroup; + } + + "use strict"; + class ViewableBuffer { + constructor(sizeOrBuffer) { + if (typeof sizeOrBuffer === "number") { + this.rawBinaryData = new ArrayBuffer(sizeOrBuffer); + } else if (sizeOrBuffer instanceof Uint8Array) { + this.rawBinaryData = sizeOrBuffer.buffer; + } else { + this.rawBinaryData = sizeOrBuffer; + } + this.uint32View = new Uint32Array(this.rawBinaryData); + this.float32View = new Float32Array(this.rawBinaryData); + this.size = this.rawBinaryData.byteLength; + } + /** View on the raw binary data as a `Int8Array`. */ + get int8View() { + if (!this._int8View) { + this._int8View = new Int8Array(this.rawBinaryData); + } + return this._int8View; + } + /** View on the raw binary data as a `Uint8Array`. */ + get uint8View() { + if (!this._uint8View) { + this._uint8View = new Uint8Array(this.rawBinaryData); + } + return this._uint8View; + } + /** View on the raw binary data as a `Int16Array`. */ + get int16View() { + if (!this._int16View) { + this._int16View = new Int16Array(this.rawBinaryData); + } + return this._int16View; + } + /** View on the raw binary data as a `Int32Array`. */ + get int32View() { + if (!this._int32View) { + this._int32View = new Int32Array(this.rawBinaryData); + } + return this._int32View; + } + /** View on the raw binary data as a `Float64Array`. */ + get float64View() { + if (!this._float64Array) { + this._float64Array = new Float64Array(this.rawBinaryData); + } + return this._float64Array; + } + /** View on the raw binary data as a `BigUint64Array`. */ + get bigUint64View() { + if (!this._bigUint64Array) { + this._bigUint64Array = new BigUint64Array(this.rawBinaryData); + } + return this._bigUint64Array; + } + /** + * Returns the view of the given type. + * @param type - One of `int8`, `uint8`, `int16`, + * `uint16`, `int32`, `uint32`, and `float32`. + * @returns - typed array of given type + */ + view(type) { + return this[`${type}View`]; + } + /** Destroys all buffer references. Do not use after calling this. */ + destroy() { + this.rawBinaryData = null; + this._int8View = null; + this._uint8View = null; + this._int16View = null; + this.uint16View = null; + this._int32View = null; + this.uint32View = null; + this.float32View = null; + } + /** + * Returns the size of the given type in bytes. + * @param type - One of `int8`, `uint8`, `int16`, + * `uint16`, `int32`, `uint32`, and `float32`. + * @returns - size of the type in bytes + */ + static sizeOf(type) { + switch (type) { + case "int8": + case "uint8": + return 1; + case "int16": + case "uint16": + return 2; + case "int32": + case "uint32": + case "float32": + return 4; + default: + throw new Error(`${type} isn't a valid view type`); + } + } + } + + "use strict"; + function fastCopy(sourceBuffer, destinationBuffer) { + const lengthDouble = sourceBuffer.byteLength / 8 | 0; + const sourceFloat64View = new Float64Array(sourceBuffer, 0, lengthDouble); + const destinationFloat64View = new Float64Array(destinationBuffer, 0, lengthDouble); + destinationFloat64View.set(sourceFloat64View); + const remainingBytes = sourceBuffer.byteLength - lengthDouble * 8; + if (remainingBytes > 0) { + const sourceUint8View = new Uint8Array(sourceBuffer, lengthDouble * 8, remainingBytes); + const destinationUint8View = new Uint8Array(destinationBuffer, lengthDouble * 8, remainingBytes); + destinationUint8View.set(sourceUint8View); + } + } + + "use strict"; + const BLEND_TO_NPM = { + normal: "normal-npm", + add: "add-npm", + screen: "screen-npm" + }; + var STENCIL_MODES = /* @__PURE__ */ ((STENCIL_MODES2) => { + STENCIL_MODES2[STENCIL_MODES2["DISABLED"] = 0] = "DISABLED"; + STENCIL_MODES2[STENCIL_MODES2["RENDERING_MASK_ADD"] = 1] = "RENDERING_MASK_ADD"; + STENCIL_MODES2[STENCIL_MODES2["MASK_ACTIVE"] = 2] = "MASK_ACTIVE"; + STENCIL_MODES2[STENCIL_MODES2["RENDERING_MASK_REMOVE"] = 3] = "RENDERING_MASK_REMOVE"; + STENCIL_MODES2[STENCIL_MODES2["NONE"] = 4] = "NONE"; + return STENCIL_MODES2; + })(STENCIL_MODES || {}); + + "use strict"; + function getAdjustedBlendModeBlend(blendMode, textureSource) { + if (textureSource.alphaMode === "no-premultiply-alpha") { + return BLEND_TO_NPM[blendMode] || blendMode; + } + return blendMode; + } + + "use strict"; + class BatchTextureArray { + constructor() { + /** Respective locations for textures. */ + this.ids = /* @__PURE__ */ Object.create(null); + this.textures = []; + this.count = 0; + } + /** Clear the textures and their locations. */ + clear() { + for (let i = 0; i < this.count; i++) { + const t = this.textures[i]; + this.textures[i] = null; + this.ids[t.uid] = null; + } + this.count = 0; + } + } + + "use strict"; + var __defProp$U = Object.defineProperty; + var __getOwnPropSymbols$U = Object.getOwnPropertySymbols; + var __hasOwnProp$U = Object.prototype.hasOwnProperty; + var __propIsEnum$U = Object.prototype.propertyIsEnumerable; + var __defNormalProp$U = (obj, key, value) => key in obj ? __defProp$U(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$U = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$U.call(b, prop)) + __defNormalProp$U(a, prop, b[prop]); + if (__getOwnPropSymbols$U) + for (var prop of __getOwnPropSymbols$U(b)) { + if (__propIsEnum$U.call(b, prop)) + __defNormalProp$U(a, prop, b[prop]); + } + return a; + }; + class Batch { + constructor() { + this.renderPipeId = "batch"; + this.action = "startBatch"; + // TODO - eventually this could be useful for flagging batches as dirty and then only rebuilding those ones + // public elementStart = 0; + // public elementSize = 0; + // for drawing.. + this.start = 0; + this.size = 0; + this.blendMode = "normal"; + this.canBundle = true; + } + destroy() { + this.textures = null; + this.gpuBindGroup = null; + this.bindGroup = null; + this.batcher = null; + } + } + let BATCH_TICK = 0; + const _Batcher = class _Batcher { + constructor(options = {}) { + this.uid = uid("batcher"); + this.dirty = true; + this.batchIndex = 0; + this.batches = []; + // specifics. + this._vertexSize = 6; + this._elements = []; + this._batchPool = []; + this._batchPoolIndex = 0; + this._textureBatchPool = []; + this._textureBatchPoolIndex = 0; + options = __spreadValues$U(__spreadValues$U({}, _Batcher.defaultOptions), options); + const { vertexSize, indexSize } = options; + this.attributeBuffer = new ViewableBuffer(vertexSize * this._vertexSize * 4); + this.indexBuffer = new Uint16Array(indexSize); + this._maxTextures = maxRecommendedTextures(); + } + begin() { + this.batchIndex = 0; + this.elementSize = 0; + this.elementStart = 0; + this.indexSize = 0; + this.attributeSize = 0; + this._batchPoolIndex = 0; + this._textureBatchPoolIndex = 0; + this._batchIndexStart = 0; + this._batchIndexSize = 0; + this.dirty = true; + } + add(batchableObject) { + this._elements[this.elementSize++] = batchableObject; + batchableObject.indexStart = this.indexSize; + batchableObject.location = this.attributeSize; + batchableObject.batcher = this; + this.indexSize += batchableObject.indexSize; + this.attributeSize += batchableObject.vertexSize * this._vertexSize; + } + checkAndUpdateTexture(batchableObject, texture) { + const textureId = batchableObject.batch.textures.ids[texture._source.uid]; + if (!textureId && textureId !== 0) + return false; + batchableObject.textureId = textureId; + batchableObject.texture = texture; + return true; + } + updateElement(batchableObject) { + this.dirty = true; + batchableObject.packAttributes( + this.attributeBuffer.float32View, + this.attributeBuffer.uint32View, + batchableObject.location, + batchableObject.textureId + ); + } + /** + * breaks the batcher. This happens when a batch gets too big, + * or we need to switch to a different type of rendering (a filter for example) + * @param instructionSet + */ + break(instructionSet) { + const elements = this._elements; + let textureBatch = this._textureBatchPool[this._textureBatchPoolIndex++] || new BatchTextureArray(); + textureBatch.clear(); + if (!elements[this.elementStart]) + return; + const firstElement = elements[this.elementStart]; + let blendMode = getAdjustedBlendModeBlend(firstElement.blendMode, firstElement.texture._source); + if (this.attributeSize * 4 > this.attributeBuffer.size) { + this._resizeAttributeBuffer(this.attributeSize * 4); + } + if (this.indexSize > this.indexBuffer.length) { + this._resizeIndexBuffer(this.indexSize); + } + const f32 = this.attributeBuffer.float32View; + const u32 = this.attributeBuffer.uint32View; + const iBuffer = this.indexBuffer; + let size = this._batchIndexSize; + let start = this._batchIndexStart; + let action = "startBatch"; + let batch = this._batchPool[this._batchPoolIndex++] || new Batch(); + const maxTextures = this._maxTextures; + for (let i = this.elementStart; i < this.elementSize; ++i) { + const element = elements[i]; + elements[i] = null; + const texture = element.texture; + const source = texture._source; + const adjustedBlendMode = getAdjustedBlendModeBlend(element.blendMode, source); + const blendModeChange = blendMode !== adjustedBlendMode; + if (source._batchTick === BATCH_TICK && !blendModeChange) { + element.textureId = source._textureBindLocation; + size += element.indexSize; + element.packAttributes(f32, u32, element.location, element.textureId); + element.packIndex(iBuffer, element.indexStart, element.location / this._vertexSize); + element.batch = batch; + continue; + } + source._batchTick = BATCH_TICK; + if (textureBatch.count >= maxTextures || blendModeChange) { + this._finishBatch( + batch, + start, + size - start, + textureBatch, + blendMode, + instructionSet, + action + ); + action = "renderBatch"; + start = size; + blendMode = adjustedBlendMode; + textureBatch = this._textureBatchPool[this._textureBatchPoolIndex++] || new BatchTextureArray(); + textureBatch.clear(); + batch = this._batchPool[this._batchPoolIndex++] || new Batch(); + ++BATCH_TICK; + } + element.textureId = source._textureBindLocation = textureBatch.count; + textureBatch.ids[source.uid] = textureBatch.count; + textureBatch.textures[textureBatch.count++] = source; + element.batch = batch; + size += element.indexSize; + element.packAttributes(f32, u32, element.location, element.textureId); + element.packIndex(iBuffer, element.indexStart, element.location / this._vertexSize); + } + if (textureBatch.count > 0) { + this._finishBatch( + batch, + start, + size - start, + textureBatch, + blendMode, + instructionSet, + action + ); + start = size; + ++BATCH_TICK; + } + this.elementStart = this.elementSize; + this._batchIndexStart = start; + this._batchIndexSize = size; + } + _finishBatch(batch, indexStart, indexSize, textureBatch, blendMode, instructionSet, action) { + batch.gpuBindGroup = null; + batch.action = action; + batch.batcher = this; + batch.textures = textureBatch; + batch.blendMode = blendMode; + batch.start = indexStart; + batch.size = indexSize; + ++BATCH_TICK; + instructionSet.add(batch); + } + finish(instructionSet) { + this.break(instructionSet); + } + /** + * Resizes the attribute buffer to the given size (1 = 1 float32) + * @param size - the size in vertices to ensure (not bytes!) + */ + ensureAttributeBuffer(size) { + if (size * 4 <= this.attributeBuffer.size) + return; + this._resizeAttributeBuffer(size * 4); + } + /** + * Resizes the index buffer to the given size (1 = 1 float32) + * @param size - the size in vertices to ensure (not bytes!) + */ + ensureIndexBuffer(size) { + if (size <= this.indexBuffer.length) + return; + this._resizeIndexBuffer(size); + } + _resizeAttributeBuffer(size) { + const newSize = Math.max(size, this.attributeBuffer.size * 2); + const newArrayBuffer = new ViewableBuffer(newSize); + fastCopy(this.attributeBuffer.rawBinaryData, newArrayBuffer.rawBinaryData); + this.attributeBuffer = newArrayBuffer; + } + _resizeIndexBuffer(size) { + const indexBuffer = this.indexBuffer; + let newSize = Math.max(size, indexBuffer.length * 1.5); + newSize += newSize % 2; + const newIndexBuffer = newSize > 65535 ? new Uint32Array(newSize) : new Uint16Array(newSize); + if (newIndexBuffer.BYTES_PER_ELEMENT !== indexBuffer.BYTES_PER_ELEMENT) { + for (let i = 0; i < indexBuffer.length; i++) { + newIndexBuffer[i] = indexBuffer[i]; + } + } else { + fastCopy(indexBuffer.buffer, newIndexBuffer.buffer); + } + this.indexBuffer = newIndexBuffer; + } + destroy() { + for (let i = 0; i < this.batches.length; i++) { + this.batches[i].destroy(); + } + this.batches = null; + for (let i = 0; i < this._elements.length; i++) { + this._elements[i].batch = null; + } + this._elements = null; + this.indexBuffer = null; + this.attributeBuffer.destroy(); + this.attributeBuffer = null; + } + }; + _Batcher.defaultOptions = { + vertexSize: 4, + indexSize: 6 + }; + let Batcher = _Batcher; + + "use strict"; + function buildUvs(vertices, verticesStride, verticesOffset, uvs, uvsOffset, uvsStride, size, matrix = null) { + let index = 0; + verticesOffset *= verticesStride; + uvsOffset *= uvsStride; + const a = matrix.a; + const b = matrix.b; + const c = matrix.c; + const d = matrix.d; + const tx = matrix.tx; + const ty = matrix.ty; + while (index < size) { + const x = vertices[verticesOffset]; + const y = vertices[verticesOffset + 1]; + uvs[uvsOffset] = a * x + c * y + tx; + uvs[uvsOffset + 1] = b * x + d * y + ty; + uvsOffset += uvsStride; + verticesOffset += verticesStride; + index++; + } + } + function buildSimpleUvs(uvs, uvsOffset, uvsStride, size) { + let index = 0; + uvsOffset *= uvsStride; + while (index < size) { + uvs[uvsOffset] = 0; + uvs[uvsOffset + 1] = 0; + uvsOffset += uvsStride; + index++; + } + } + + "use strict"; + function transformVertices(vertices, m, offset, stride, size) { + const a = m.a; + const b = m.b; + const c = m.c; + const d = m.d; + const tx = m.tx; + const ty = m.ty; + offset = offset || 0; + stride = stride || 2; + size = size || vertices.length / stride - offset; + let index = offset * stride; + for (let i = 0; i < size; i++) { + const x = vertices[index]; + const y = vertices[index + 1]; + vertices[index] = a * x + c * y + tx; + vertices[index + 1] = b * x + d * y + ty; + index += stride; + } + } + + "use strict"; + function multiplyHexColors(color1, color2) { + if (color1 === 16777215 || !color2) + return color2; + if (color2 === 16777215 || !color1) + return color1; + const r1 = color1 >> 16 & 255; + const g1 = color1 >> 8 & 255; + const b1 = color1 & 255; + const r2 = color2 >> 16 & 255; + const g2 = color2 >> 8 & 255; + const b2 = color2 & 255; + const r = r1 * r2 / 255; + const g = g1 * g2 / 255; + const b = b1 * b2 / 255; + return (r << 16) + (g << 8) + b; + } + + "use strict"; + class BatchableGraphics { + constructor() { + this.batcher = null; + this.batch = null; + this.applyTransform = true; + this.roundPixels = 0; + } + get blendMode() { + if (this.applyTransform) { + return this.renderable.groupBlendMode; + } + return "normal"; + } + packIndex(indexBuffer, index, indicesOffset) { + const indices = this.geometryData.indices; + for (let i = 0; i < this.indexSize; i++) { + indexBuffer[index++] = indices[i + this.indexOffset] + indicesOffset - this.vertexOffset; + } + } + packAttributes(float32View, uint32View, index, textureId) { + const geometry = this.geometryData; + const graphics = this.renderable; + const positions = geometry.vertices; + const uvs = geometry.uvs; + const offset = this.vertexOffset * 2; + const vertSize = (this.vertexOffset + this.vertexSize) * 2; + const rgb = this.color; + const bgr = rgb >> 16 | rgb & 65280 | (rgb & 255) << 16; + if (this.applyTransform) { + const argb = multiplyHexColors(bgr, graphics.groupColor) + (this.alpha * graphics.groupAlpha * 255 << 24); + const wt = graphics.groupTransform; + const textureIdAndRound = textureId << 16 | this.roundPixels & 65535; + const a = wt.a; + const b = wt.b; + const c = wt.c; + const d = wt.d; + const tx = wt.tx; + const ty = wt.ty; + for (let i = offset; i < vertSize; i += 2) { + const x = positions[i]; + const y = positions[i + 1]; + float32View[index] = a * x + c * y + tx; + float32View[index + 1] = b * x + d * y + ty; + float32View[index + 2] = uvs[i]; + float32View[index + 3] = uvs[i + 1]; + uint32View[index + 4] = argb; + uint32View[index + 5] = textureIdAndRound; + index += 6; + } + } else { + const argb = bgr + (this.alpha * 255 << 24); + for (let i = offset; i < vertSize; i += 2) { + float32View[index] = positions[i]; + float32View[index + 1] = positions[i + 1]; + float32View[index + 2] = uvs[i]; + float32View[index + 3] = uvs[i + 1]; + uint32View[index + 4] = argb; + uint32View[index + 5] = textureId << 16; + index += 6; + } + } + } + // TODO rename to vertexSize + get vertSize() { + return this.vertexSize; + } + copyTo(gpuBuffer) { + gpuBuffer.indexOffset = this.indexOffset; + gpuBuffer.indexSize = this.indexSize; + gpuBuffer.vertexOffset = this.vertexOffset; + gpuBuffer.vertexSize = this.vertexSize; + gpuBuffer.color = this.color; + gpuBuffer.alpha = this.alpha; + gpuBuffer.texture = this.texture; + gpuBuffer.geometryData = this.geometryData; + } + reset() { + this.applyTransform = true; + } + } + + "use strict"; + const buildCircle = { + build(shape, points) { + let x; + let y; + let dx; + let dy; + let rx; + let ry; + if (shape.type === "circle") { + const circle = shape; + x = circle.x; + y = circle.y; + rx = ry = circle.radius; + dx = dy = 0; + } else if (shape.type === "ellipse") { + const ellipse = shape; + x = ellipse.x; + y = ellipse.y; + rx = ellipse.halfWidth; + ry = ellipse.halfHeight; + dx = dy = 0; + } else { + const roundedRect = shape; + const halfWidth = roundedRect.width / 2; + const halfHeight = roundedRect.height / 2; + x = roundedRect.x + halfWidth; + y = roundedRect.y + halfHeight; + rx = ry = Math.max(0, Math.min(roundedRect.radius, Math.min(halfWidth, halfHeight))); + dx = halfWidth - rx; + dy = halfHeight - ry; + } + if (!(rx >= 0 && ry >= 0 && dx >= 0 && dy >= 0)) { + return points; + } + const n = Math.ceil(2.3 * Math.sqrt(rx + ry)); + const m = n * 8 + (dx ? 4 : 0) + (dy ? 4 : 0); + if (m === 0) { + return points; + } + if (n === 0) { + points[0] = points[6] = x + dx; + points[1] = points[3] = y + dy; + points[2] = points[4] = x - dx; + points[5] = points[7] = y - dy; + return points; + } + let j1 = 0; + let j2 = n * 4 + (dx ? 2 : 0) + 2; + let j3 = j2; + let j4 = m; + let x0 = dx + rx; + let y0 = dy; + let x1 = x + x0; + let x2 = x - x0; + let y1 = y + y0; + points[j1++] = x1; + points[j1++] = y1; + points[--j2] = y1; + points[--j2] = x2; + if (dy) { + const y22 = y - y0; + points[j3++] = x2; + points[j3++] = y22; + points[--j4] = y22; + points[--j4] = x1; + } + for (let i = 1; i < n; i++) { + const a = Math.PI / 2 * (i / n); + const x02 = dx + Math.cos(a) * rx; + const y02 = dy + Math.sin(a) * ry; + const x12 = x + x02; + const x22 = x - x02; + const y12 = y + y02; + const y22 = y - y02; + points[j1++] = x12; + points[j1++] = y12; + points[--j2] = y12; + points[--j2] = x22; + points[j3++] = x22; + points[j3++] = y22; + points[--j4] = y22; + points[--j4] = x12; + } + x0 = dx; + y0 = dy + ry; + x1 = x + x0; + x2 = x - x0; + y1 = y + y0; + const y2 = y - y0; + points[j1++] = x1; + points[j1++] = y1; + points[--j4] = y2; + points[--j4] = x1; + if (dx) { + points[j1++] = x2; + points[j1++] = y1; + points[--j4] = y2; + points[--j4] = x2; + } + return points; + }, + triangulate(points, vertices, verticesStride, verticesOffset, indices, indicesOffset) { + if (points.length === 0) { + return; + } + let centerX = 0; + let centerY = 0; + for (let i = 0; i < points.length; i += 2) { + centerX += points[i]; + centerY += points[i + 1]; + } + centerX /= points.length / 2; + centerY /= points.length / 2; + let count = verticesOffset; + vertices[count * verticesStride] = centerX; + vertices[count * verticesStride + 1] = centerY; + const centerIndex = count++; + for (let i = 0; i < points.length; i += 2) { + vertices[count * verticesStride] = points[i]; + vertices[count * verticesStride + 1] = points[i + 1]; + if (i > 0) { + indices[indicesOffset++] = count; + indices[indicesOffset++] = centerIndex; + indices[indicesOffset++] = count - 1; + } + count++; + } + indices[indicesOffset++] = centerIndex + 1; + indices[indicesOffset++] = centerIndex; + indices[indicesOffset++] = count - 1; + } + }; + + "use strict"; + const closePointEps = 1e-4; + const curveEps = 1e-4; + + "use strict"; + function getOrientationOfPoints(points) { + const m = points.length; + if (m < 6) { + return 1; + } + let area = 0; + for (let i = 0, x1 = points[m - 2], y1 = points[m - 1]; i < m; i += 2) { + const x2 = points[i]; + const y2 = points[i + 1]; + area += (x2 - x1) * (y2 + y1); + x1 = x2; + y1 = y2; + } + if (area < 0) { + return -1; + } + return 1; + } + + "use strict"; + function square(x, y, nx, ny, innerWeight, outerWeight, clockwise, verts) { + const ix = x - nx * innerWeight; + const iy = y - ny * innerWeight; + const ox = x + nx * outerWeight; + const oy = y + ny * outerWeight; + let exx; + let eyy; + if (clockwise) { + exx = ny; + eyy = -nx; + } else { + exx = -ny; + eyy = nx; + } + const eix = ix + exx; + const eiy = iy + eyy; + const eox = ox + exx; + const eoy = oy + eyy; + verts.push(eix, eiy); + verts.push(eox, eoy); + return 2; + } + function round(cx, cy, sx, sy, ex, ey, verts, clockwise) { + const cx2p0x = sx - cx; + const cy2p0y = sy - cy; + let angle0 = Math.atan2(cx2p0x, cy2p0y); + let angle1 = Math.atan2(ex - cx, ey - cy); + if (clockwise && angle0 < angle1) { + angle0 += Math.PI * 2; + } else if (!clockwise && angle0 > angle1) { + angle1 += Math.PI * 2; + } + let startAngle = angle0; + const angleDiff = angle1 - angle0; + const absAngleDiff = Math.abs(angleDiff); + const radius = Math.sqrt(cx2p0x * cx2p0x + cy2p0y * cy2p0y); + const segCount = (15 * absAngleDiff * Math.sqrt(radius) / Math.PI >> 0) + 1; + const angleInc = angleDiff / segCount; + startAngle += angleInc; + if (clockwise) { + verts.push(cx, cy); + verts.push(sx, sy); + for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) { + verts.push(cx, cy); + verts.push( + cx + Math.sin(angle) * radius, + cy + Math.cos(angle) * radius + ); + } + verts.push(cx, cy); + verts.push(ex, ey); + } else { + verts.push(sx, sy); + verts.push(cx, cy); + for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) { + verts.push( + cx + Math.sin(angle) * radius, + cy + Math.cos(angle) * radius + ); + verts.push(cx, cy); + } + verts.push(ex, ey); + verts.push(cx, cy); + } + return segCount * 2; + } + function buildLine(points, lineStyle, flipAlignment, closed, vertices, _verticesStride, _verticesOffset, indices, _indicesOffset) { + const eps = closePointEps; + if (points.length === 0) { + return; + } + const style = lineStyle; + let alignment = style.alignment; + if (lineStyle.alignment !== 0.5) { + let orientation = getOrientationOfPoints(points); + if (flipAlignment) + orientation *= -1; + alignment = (alignment - 0.5) * orientation + 0.5; + } + const firstPoint = new Point(points[0], points[1]); + const lastPoint = new Point(points[points.length - 2], points[points.length - 1]); + const closedShape = closed; + const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps && Math.abs(firstPoint.y - lastPoint.y) < eps; + if (closedShape) { + points = points.slice(); + if (closedPath) { + points.pop(); + points.pop(); + lastPoint.set(points[points.length - 2], points[points.length - 1]); + } + const midPointX = (firstPoint.x + lastPoint.x) * 0.5; + const midPointY = (lastPoint.y + firstPoint.y) * 0.5; + points.unshift(midPointX, midPointY); + points.push(midPointX, midPointY); + } + const verts = vertices; + const length = points.length / 2; + let indexCount = points.length; + const indexStart = verts.length / 2; + const width = style.width / 2; + const widthSquared = width * width; + const miterLimitSquared = style.miterLimit * style.miterLimit; + let x0 = points[0]; + let y0 = points[1]; + let x1 = points[2]; + let y1 = points[3]; + let x2 = 0; + let y2 = 0; + let perpX = -(y0 - y1); + let perpY = x0 - x1; + let perp1x = 0; + let perp1y = 0; + let dist = Math.sqrt(perpX * perpX + perpY * perpY); + perpX /= dist; + perpY /= dist; + perpX *= width; + perpY *= width; + const ratio = alignment; + const innerWeight = (1 - ratio) * 2; + const outerWeight = ratio * 2; + if (!closedShape) { + if (style.cap === "round") { + indexCount += round( + x0 - perpX * (innerWeight - outerWeight) * 0.5, + y0 - perpY * (innerWeight - outerWeight) * 0.5, + x0 - perpX * innerWeight, + y0 - perpY * innerWeight, + x0 + perpX * outerWeight, + y0 + perpY * outerWeight, + verts, + true + ) + 2; + } else if (style.cap === "square") { + indexCount += square(x0, y0, perpX, perpY, innerWeight, outerWeight, true, verts); + } + } + verts.push( + x0 - perpX * innerWeight, + y0 - perpY * innerWeight + ); + verts.push( + x0 + perpX * outerWeight, + y0 + perpY * outerWeight + ); + for (let i = 1; i < length - 1; ++i) { + x0 = points[(i - 1) * 2]; + y0 = points[(i - 1) * 2 + 1]; + x1 = points[i * 2]; + y1 = points[i * 2 + 1]; + x2 = points[(i + 1) * 2]; + y2 = points[(i + 1) * 2 + 1]; + perpX = -(y0 - y1); + perpY = x0 - x1; + dist = Math.sqrt(perpX * perpX + perpY * perpY); + perpX /= dist; + perpY /= dist; + perpX *= width; + perpY *= width; + perp1x = -(y1 - y2); + perp1y = x1 - x2; + dist = Math.sqrt(perp1x * perp1x + perp1y * perp1y); + perp1x /= dist; + perp1y /= dist; + perp1x *= width; + perp1y *= width; + const dx0 = x1 - x0; + const dy0 = y0 - y1; + const dx1 = x1 - x2; + const dy1 = y2 - y1; + const dot = dx0 * dx1 + dy0 * dy1; + const cross = dy0 * dx1 - dy1 * dx0; + const clockwise = cross < 0; + if (Math.abs(cross) < 1e-3 * Math.abs(dot)) { + verts.push( + x1 - perpX * innerWeight, + y1 - perpY * innerWeight + ); + verts.push( + x1 + perpX * outerWeight, + y1 + perpY * outerWeight + ); + if (dot >= 0) { + if (style.join === "round") { + indexCount += round( + x1, + y1, + x1 - perpX * innerWeight, + y1 - perpY * innerWeight, + x1 - perp1x * innerWeight, + y1 - perp1y * innerWeight, + verts, + false + ) + 4; + } else { + indexCount += 2; + } + verts.push( + x1 - perp1x * outerWeight, + y1 - perp1y * outerWeight + ); + verts.push( + x1 + perp1x * innerWeight, + y1 + perp1y * innerWeight + ); + } + continue; + } + const c1 = (-perpX + x0) * (-perpY + y1) - (-perpX + x1) * (-perpY + y0); + const c2 = (-perp1x + x2) * (-perp1y + y1) - (-perp1x + x1) * (-perp1y + y2); + const px = (dx0 * c2 - dx1 * c1) / cross; + const py = (dy1 * c1 - dy0 * c2) / cross; + const pDist = (px - x1) * (px - x1) + (py - y1) * (py - y1); + const imx = x1 + (px - x1) * innerWeight; + const imy = y1 + (py - y1) * innerWeight; + const omx = x1 - (px - x1) * outerWeight; + const omy = y1 - (py - y1) * outerWeight; + const smallerInsideSegmentSq = Math.min(dx0 * dx0 + dy0 * dy0, dx1 * dx1 + dy1 * dy1); + const insideWeight = clockwise ? innerWeight : outerWeight; + const smallerInsideDiagonalSq = smallerInsideSegmentSq + insideWeight * insideWeight * widthSquared; + const insideMiterOk = pDist <= smallerInsideDiagonalSq; + if (insideMiterOk) { + if (style.join === "bevel" || pDist / widthSquared > miterLimitSquared) { + if (clockwise) { + verts.push(imx, imy); + verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight); + verts.push(imx, imy); + verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight); + } else { + verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight); + verts.push(omx, omy); + verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight); + verts.push(omx, omy); + } + indexCount += 2; + } else if (style.join === "round") { + if (clockwise) { + verts.push(imx, imy); + verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight); + indexCount += round( + x1, + y1, + x1 + perpX * outerWeight, + y1 + perpY * outerWeight, + x1 + perp1x * outerWeight, + y1 + perp1y * outerWeight, + verts, + true + ) + 4; + verts.push(imx, imy); + verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight); + } else { + verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight); + verts.push(omx, omy); + indexCount += round( + x1, + y1, + x1 - perpX * innerWeight, + y1 - perpY * innerWeight, + x1 - perp1x * innerWeight, + y1 - perp1y * innerWeight, + verts, + false + ) + 4; + verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight); + verts.push(omx, omy); + } + } else { + verts.push(imx, imy); + verts.push(omx, omy); + } + } else { + verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight); + verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight); + if (style.join === "round") { + if (clockwise) { + indexCount += round( + x1, + y1, + x1 + perpX * outerWeight, + y1 + perpY * outerWeight, + x1 + perp1x * outerWeight, + y1 + perp1y * outerWeight, + verts, + true + ) + 2; + } else { + indexCount += round( + x1, + y1, + x1 - perpX * innerWeight, + y1 - perpY * innerWeight, + x1 - perp1x * innerWeight, + y1 - perp1y * innerWeight, + verts, + false + ) + 2; + } + } else if (style.join === "miter" && pDist / widthSquared <= miterLimitSquared) { + if (clockwise) { + verts.push(omx, omy); + verts.push(omx, omy); + } else { + verts.push(imx, imy); + verts.push(imx, imy); + } + indexCount += 2; + } + verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight); + verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight); + indexCount += 2; + } + } + x0 = points[(length - 2) * 2]; + y0 = points[(length - 2) * 2 + 1]; + x1 = points[(length - 1) * 2]; + y1 = points[(length - 1) * 2 + 1]; + perpX = -(y0 - y1); + perpY = x0 - x1; + dist = Math.sqrt(perpX * perpX + perpY * perpY); + perpX /= dist; + perpY /= dist; + perpX *= width; + perpY *= width; + verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight); + verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight); + if (!closedShape) { + if (style.cap === "round") { + indexCount += round( + x1 - perpX * (innerWeight - outerWeight) * 0.5, + y1 - perpY * (innerWeight - outerWeight) * 0.5, + x1 - perpX * innerWeight, + y1 - perpY * innerWeight, + x1 + perpX * outerWeight, + y1 + perpY * outerWeight, + verts, + false + ) + 2; + } else if (style.cap === "square") { + indexCount += square(x1, y1, perpX, perpY, innerWeight, outerWeight, false, verts); + } + } + const eps2 = curveEps * curveEps; + for (let i = indexStart; i < indexCount + indexStart - 2; ++i) { + x0 = verts[i * 2]; + y0 = verts[i * 2 + 1]; + x1 = verts[(i + 1) * 2]; + y1 = verts[(i + 1) * 2 + 1]; + x2 = verts[(i + 2) * 2]; + y2 = verts[(i + 2) * 2 + 1]; + if (Math.abs(x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)) < eps2) { + continue; + } + indices.push(i, i + 1, i + 2); + } + } + + var earcut$2 = {exports: {}}; + + var earcut_1 = earcut$2.exports; + + 'use strict'; + + earcut$2.exports = earcut; + var _default = earcut$2.exports.default = earcut; + + function earcut(data, holeIndices, dim) { + + dim = dim || 2; + + var hasHoles = holeIndices && holeIndices.length, + outerLen = hasHoles ? holeIndices[0] * dim : data.length, + outerNode = linkedList(data, 0, outerLen, dim, true), + triangles = []; + + if (!outerNode || outerNode.next === outerNode.prev) return triangles; + + var minX, minY, maxX, maxY, x, y, invSize; + + if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); + + // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox + if (data.length > 80 * dim) { + minX = maxX = data[0]; + minY = maxY = data[1]; + + for (var i = dim; i < outerLen; i += dim) { + x = data[i]; + y = data[i + 1]; + if (x < minX) minX = x; + if (y < minY) minY = y; + if (x > maxX) maxX = x; + if (y > maxY) maxY = y; + } + + // minX, minY and invSize are later used to transform coords into integers for z-order calculation + invSize = Math.max(maxX - minX, maxY - minY); + invSize = invSize !== 0 ? 32767 / invSize : 0; + } + + earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0); + + return triangles; + } + + // create a circular doubly linked list from polygon points in the specified winding order + function linkedList(data, start, end, dim, clockwise) { + var i, last; + + if (clockwise === (signedArea(data, start, end, dim) > 0)) { + for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last); + } else { + for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last); + } + + if (last && equals(last, last.next)) { + removeNode(last); + last = last.next; + } + + return last; + } + + // eliminate colinear or duplicate points + function filterPoints(start, end) { + if (!start) return start; + if (!end) end = start; + + var p = start, + again; + do { + again = false; + + if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { + removeNode(p); + p = end = p.prev; + if (p === p.next) break; + again = true; + + } else { + p = p.next; + } + } while (again || p !== end); + + return end; + } + + // main ear slicing loop which triangulates a polygon (given as a linked list) + function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { + if (!ear) return; + + // interlink polygon nodes in z-order + if (!pass && invSize) indexCurve(ear, minX, minY, invSize); + + var stop = ear, + prev, next; + + // iterate through ears, slicing them one by one + while (ear.prev !== ear.next) { + prev = ear.prev; + next = ear.next; + + if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { + // cut off the triangle + triangles.push(prev.i / dim | 0); + triangles.push(ear.i / dim | 0); + triangles.push(next.i / dim | 0); + + removeNode(ear); + + // skipping the next vertex leads to less sliver triangles + ear = next.next; + stop = next.next; + + continue; + } + + ear = next; + + // if we looped through the whole remaining polygon and can't find any more ears + if (ear === stop) { + // try filtering points and slicing again + if (!pass) { + earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); + + // if this didn't work, try curing all small self-intersections locally + } else if (pass === 1) { + ear = cureLocalIntersections(filterPoints(ear), triangles, dim); + earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); + + // as a last resort, try splitting the remaining polygon into two + } else if (pass === 2) { + splitEarcut(ear, triangles, dim, minX, minY, invSize); + } + + break; + } + } + } + + // check whether a polygon node forms a valid ear with adjacent nodes + function isEar(ear) { + var a = ear.prev, + b = ear, + c = ear.next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + // now make sure we don't have other points inside the potential ear + var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; + + // triangle bbox; min & max are calculated like this for speed + var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx), + y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy), + x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx), + y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy); + + var p = c.next; + while (p !== a) { + if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && + pointInTriangle$1(ax, ay, bx, by, cx, cy, p.x, p.y) && + area(p.prev, p, p.next) >= 0) return false; + p = p.next; + } + + return true; + } + + function isEarHashed(ear, minX, minY, invSize) { + var a = ear.prev, + b = ear, + c = ear.next; + + if (area(a, b, c) >= 0) return false; // reflex, can't be an ear + + var ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; + + // triangle bbox; min & max are calculated like this for speed + var x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx), + y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy), + x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx), + y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy); + + // z-order range for the current triangle bbox; + var minZ = zOrder(x0, y0, minX, minY, invSize), + maxZ = zOrder(x1, y1, minX, minY, invSize); + + var p = ear.prevZ, + n = ear.nextZ; + + // look for points inside the triangle in both directions + while (p && p.z >= minZ && n && n.z <= maxZ) { + if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && + pointInTriangle$1(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; + p = p.prevZ; + + if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && + pointInTriangle$1(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; + n = n.nextZ; + } + + // look for remaining points in decreasing z-order + while (p && p.z >= minZ) { + if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && + pointInTriangle$1(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; + p = p.prevZ; + } + + // look for remaining points in increasing z-order + while (n && n.z <= maxZ) { + if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && + pointInTriangle$1(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; + n = n.nextZ; + } + + return true; + } + + // go through all polygon nodes and cure small local self-intersections + function cureLocalIntersections(start, triangles, dim) { + var p = start; + do { + var a = p.prev, + b = p.next.next; + + if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { + + triangles.push(a.i / dim | 0); + triangles.push(p.i / dim | 0); + triangles.push(b.i / dim | 0); + + // remove two nodes involved + removeNode(p); + removeNode(p.next); + + p = start = b; + } + p = p.next; + } while (p !== start); + + return filterPoints(p); + } + + // try splitting polygon into two and triangulate them independently + function splitEarcut(start, triangles, dim, minX, minY, invSize) { + // look for a valid diagonal that divides the polygon into two + var a = start; + do { + var b = a.next.next; + while (b !== a.prev) { + if (a.i !== b.i && isValidDiagonal(a, b)) { + // split the polygon in two by the diagonal + var c = splitPolygon(a, b); + + // filter colinear points around the cuts + a = filterPoints(a, a.next); + c = filterPoints(c, c.next); + + // run earcut on each half + earcutLinked(a, triangles, dim, minX, minY, invSize, 0); + earcutLinked(c, triangles, dim, minX, minY, invSize, 0); + return; + } + b = b.next; + } + a = a.next; + } while (a !== start); + } + + // link every hole into the outer loop, producing a single-ring polygon without holes + function eliminateHoles(data, holeIndices, outerNode, dim) { + var queue = [], + i, len, start, end, list; + + for (i = 0, len = holeIndices.length; i < len; i++) { + start = holeIndices[i] * dim; + end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + list = linkedList(data, start, end, dim, false); + if (list === list.next) list.steiner = true; + queue.push(getLeftmost(list)); + } + + queue.sort(compareX); + + // process holes from left to right + for (i = 0; i < queue.length; i++) { + outerNode = eliminateHole(queue[i], outerNode); + } + + return outerNode; + } + + function compareX(a, b) { + return a.x - b.x; + } + + // find a bridge between vertices that connects hole with an outer ring and and link it + function eliminateHole(hole, outerNode) { + var bridge = findHoleBridge(hole, outerNode); + if (!bridge) { + return outerNode; + } + + var bridgeReverse = splitPolygon(bridge, hole); + + // filter collinear points around the cuts + filterPoints(bridgeReverse, bridgeReverse.next); + return filterPoints(bridge, bridge.next); + } + + // David Eberly's algorithm for finding a bridge between hole and outer polygon + function findHoleBridge(hole, outerNode) { + var p = outerNode, + hx = hole.x, + hy = hole.y, + qx = -Infinity, + m; + + // find a segment intersected by a ray from the hole's leftmost point to the left; + // segment's endpoint with lesser x will be potential connection point + do { + if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) { + var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); + if (x <= hx && x > qx) { + qx = x; + m = p.x < p.next.x ? p : p.next; + if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint + } + } + p = p.next; + } while (p !== outerNode); + + if (!m) return null; + + // look for points inside the triangle of hole point, segment intersection and endpoint; + // if there are no points found, we have a valid connection; + // otherwise choose the point of the minimum angle with the ray as connection point + + var stop = m, + mx = m.x, + my = m.y, + tanMin = Infinity, + tan; + + p = m; + + do { + if (hx >= p.x && p.x >= mx && hx !== p.x && + pointInTriangle$1(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { + + tan = Math.abs(hy - p.y) / (hx - p.x); // tangential + + if (locallyInside(p, hole) && + (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) { + m = p; + tanMin = tan; + } + } + + p = p.next; + } while (p !== stop); + + return m; + } + + // whether sector in vertex m contains sector in vertex p in the same coordinates + function sectorContainsSector(m, p) { + return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; + } + + // interlink polygon nodes in z-order + function indexCurve(start, minX, minY, invSize) { + var p = start; + do { + if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); + p.prevZ = p.prev; + p.nextZ = p.next; + p = p.next; + } while (p !== start); + + p.prevZ.nextZ = null; + p.prevZ = null; + + sortLinked(p); + } + + // Simon Tatham's linked list merge sort algorithm + // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html + function sortLinked(list) { + var i, p, q, e, tail, numMerges, pSize, qSize, + inSize = 1; + + do { + p = list; + list = null; + tail = null; + numMerges = 0; + + while (p) { + numMerges++; + q = p; + pSize = 0; + for (i = 0; i < inSize; i++) { + pSize++; + q = q.nextZ; + if (!q) break; + } + qSize = inSize; + + while (pSize > 0 || (qSize > 0 && q)) { + + if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { + e = p; + p = p.nextZ; + pSize--; + } else { + e = q; + q = q.nextZ; + qSize--; + } + + if (tail) tail.nextZ = e; + else list = e; + + e.prevZ = tail; + tail = e; + } + + p = q; + } + + tail.nextZ = null; + inSize *= 2; + + } while (numMerges > 1); + + return list; + } + + // z-order of a point given coords and inverse of the longer side of data bbox + function zOrder(x, y, minX, minY, invSize) { + // coords are transformed into non-negative 15-bit integer range + x = (x - minX) * invSize | 0; + y = (y - minY) * invSize | 0; + + x = (x | (x << 8)) & 0x00FF00FF; + x = (x | (x << 4)) & 0x0F0F0F0F; + x = (x | (x << 2)) & 0x33333333; + x = (x | (x << 1)) & 0x55555555; + + y = (y | (y << 8)) & 0x00FF00FF; + y = (y | (y << 4)) & 0x0F0F0F0F; + y = (y | (y << 2)) & 0x33333333; + y = (y | (y << 1)) & 0x55555555; + + return x | (y << 1); + } + + // find the leftmost node of a polygon ring + function getLeftmost(start) { + var p = start, + leftmost = start; + do { + if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p; + p = p.next; + } while (p !== start); + + return leftmost; + } + + // check if a point lies within a convex triangle + function pointInTriangle$1(ax, ay, bx, by, cx, cy, px, py) { + return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && + (ax - px) * (by - py) >= (bx - px) * (ay - py) && + (bx - px) * (cy - py) >= (cx - px) * (by - py); + } + + // check if a diagonal between two polygon nodes is valid (lies in polygon interior) + function isValidDiagonal(a, b) { + return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges + (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible + (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors + equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case + } + + // signed area of a triangle + function area(p, q, r) { + return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); + } + + // check if two points are equal + function equals(p1, p2) { + return p1.x === p2.x && p1.y === p2.y; + } + + // check if two segments intersect + function intersects(p1, q1, p2, q2) { + var o1 = sign(area(p1, q1, p2)); + var o2 = sign(area(p1, q1, q2)); + var o3 = sign(area(p2, q2, p1)); + var o4 = sign(area(p2, q2, q1)); + + if (o1 !== o2 && o3 !== o4) return true; // general case + + if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 + if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 + if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 + if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 + + return false; + } + + // for collinear points p, q, r, check if point q lies on segment pr + function onSegment(p, q, r) { + return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y); + } + + function sign(num) { + return num > 0 ? 1 : num < 0 ? -1 : 0; + } + + // check if a polygon diagonal intersects any polygon segments + function intersectsPolygon(a, b) { + var p = a; + do { + if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && + intersects(p, p.next, a, b)) return true; + p = p.next; + } while (p !== a); + + return false; + } + + // check if a polygon diagonal is locally inside the polygon + function locallyInside(a, b) { + return area(a.prev, a, a.next) < 0 ? + area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : + area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; + } + + // check if the middle point of a polygon diagonal is inside the polygon + function middleInside(a, b) { + var p = a, + inside = false, + px = (a.x + b.x) / 2, + py = (a.y + b.y) / 2; + do { + if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y && + (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)) + inside = !inside; + p = p.next; + } while (p !== a); + + return inside; + } + + // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; + // if one belongs to the outer ring and another to a hole, it merges it into a single ring + function splitPolygon(a, b) { + var a2 = new Node(a.i, a.x, a.y), + b2 = new Node(b.i, b.x, b.y), + an = a.next, + bp = b.prev; + + a.next = b; + b.prev = a; + + a2.next = an; + an.prev = a2; + + b2.next = a2; + a2.prev = b2; + + bp.next = b2; + b2.prev = bp; + + return b2; + } + + // create a node and optionally link it with previous one (in a circular doubly linked list) + function insertNode(i, x, y, last) { + var p = new Node(i, x, y); + + if (!last) { + p.prev = p; + p.next = p; + + } else { + p.next = last.next; + p.prev = last; + last.next.prev = p; + last.next = p; + } + return p; + } + + function removeNode(p) { + p.next.prev = p.prev; + p.prev.next = p.next; + + if (p.prevZ) p.prevZ.nextZ = p.nextZ; + if (p.nextZ) p.nextZ.prevZ = p.prevZ; + } + + function Node(i, x, y) { + // vertex index in coordinates array + this.i = i; + + // vertex coordinates + this.x = x; + this.y = y; + + // previous and next vertex nodes in a polygon ring + this.prev = null; + this.next = null; + + // z-order curve value + this.z = 0; + + // previous and next nodes in z-order + this.prevZ = null; + this.nextZ = null; + + // indicates whether this is a steiner point + this.steiner = false; + } + + // return a percentage difference between the polygon area and its triangulation area; + // used to verify correctness of triangulation + earcut.deviation = function (data, holeIndices, dim, triangles) { + var hasHoles = holeIndices && holeIndices.length; + var outerLen = hasHoles ? holeIndices[0] * dim : data.length; + + var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim)); + if (hasHoles) { + for (var i = 0, len = holeIndices.length; i < len; i++) { + var start = holeIndices[i] * dim; + var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; + polygonArea -= Math.abs(signedArea(data, start, end, dim)); + } + } + + var trianglesArea = 0; + for (i = 0; i < triangles.length; i += 3) { + var a = triangles[i] * dim; + var b = triangles[i + 1] * dim; + var c = triangles[i + 2] * dim; + trianglesArea += Math.abs( + (data[a] - data[c]) * (data[b + 1] - data[a + 1]) - + (data[a] - data[b]) * (data[c + 1] - data[a + 1])); + } + + return polygonArea === 0 && trianglesArea === 0 ? 0 : + Math.abs((trianglesArea - polygonArea) / polygonArea); + }; + + function signedArea(data, start, end, dim) { + var sum = 0; + for (var i = start, j = end - dim; i < end; i += dim) { + sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); + j = i; + } + return sum; + } + + // turn a polygon in a multi-dimensional array form (e.g. as in GeoJSON) into a form Earcut accepts + earcut.flatten = function (data) { + var dim = data[0][0].length, + result = {vertices: [], holes: [], dimensions: dim}, + holeIndex = 0; + + for (var i = 0; i < data.length; i++) { + for (var j = 0; j < data[i].length; j++) { + for (var d = 0; d < dim; d++) result.vertices.push(data[i][j][d]); + } + if (i > 0) { + holeIndex += data[i - 1].length; + result.holes.push(holeIndex); + } + } + return result; + }; + + var earcutExports = earcut$2.exports; + var earcut$1 = /*@__PURE__*/getDefaultExportFromCjs(earcutExports); + + "use strict"; + function triangulateWithHoles(points, holes, vertices, verticesStride, verticesOffset, indices, indicesOffset) { + const triangles = earcut$1(points, holes, 2); + if (!triangles) { + return; + } + for (let i = 0; i < triangles.length; i += 3) { + indices[indicesOffset++] = triangles[i] + verticesOffset; + indices[indicesOffset++] = triangles[i + 1] + verticesOffset; + indices[indicesOffset++] = triangles[i + 2] + verticesOffset; + } + let index = verticesOffset * verticesStride; + for (let i = 0; i < points.length; i += 2) { + vertices[index] = points[i]; + vertices[index + 1] = points[i + 1]; + index += verticesStride; + } + } + + "use strict"; + const emptyArray = []; + const buildPolygon = { + build(shape, points) { + for (let i = 0; i < shape.points.length; i++) { + points[i] = shape.points[i]; + } + return points; + }, + triangulate(points, vertices, verticesStride, verticesOffset, indices, indicesOffset) { + triangulateWithHoles(points, emptyArray, vertices, verticesStride, verticesOffset, indices, indicesOffset); + } + }; + + "use strict"; + const buildRectangle = { + build(shape, points) { + const rectData = shape; + const x = rectData.x; + const y = rectData.y; + const width = rectData.width; + const height = rectData.height; + if (!(width >= 0 && height >= 0)) { + return points; + } + points[0] = x; + points[1] = y; + points[2] = x + width; + points[3] = y; + points[4] = x + width; + points[5] = y + height; + points[6] = x; + points[7] = y + height; + return points; + }, + triangulate(points, vertices, verticesStride, verticesOffset, indices, indicesOffset) { + let count = 0; + verticesOffset *= verticesStride; + vertices[verticesOffset + count] = points[0]; + vertices[verticesOffset + count + 1] = points[1]; + count += verticesStride; + vertices[verticesOffset + count] = points[2]; + vertices[verticesOffset + count + 1] = points[3]; + count += verticesStride; + vertices[verticesOffset + count] = points[6]; + vertices[verticesOffset + count + 1] = points[7]; + count += verticesStride; + vertices[verticesOffset + count] = points[4]; + vertices[verticesOffset + count + 1] = points[5]; + count += verticesStride; + const verticesIndex = verticesOffset / verticesStride; + indices[indicesOffset++] = verticesIndex; + indices[indicesOffset++] = verticesIndex + 1; + indices[indicesOffset++] = verticesIndex + 2; + indices[indicesOffset++] = verticesIndex + 1; + indices[indicesOffset++] = verticesIndex + 3; + indices[indicesOffset++] = verticesIndex + 2; + } + }; + + "use strict"; + const buildTriangle = { + build(shape, points) { + points[0] = shape.x; + points[1] = shape.y; + points[2] = shape.x2; + points[3] = shape.y2; + points[4] = shape.x3; + points[5] = shape.y3; + return points; + }, + triangulate(points, vertices, verticesStride, verticesOffset, indices, indicesOffset) { + let count = 0; + verticesOffset *= verticesStride; + vertices[verticesOffset + count] = points[0]; + vertices[verticesOffset + count + 1] = points[1]; + count += verticesStride; + vertices[verticesOffset + count] = points[2]; + vertices[verticesOffset + count + 1] = points[3]; + count += verticesStride; + vertices[verticesOffset + count] = points[4]; + vertices[verticesOffset + count + 1] = points[5]; + const verticesIndex = verticesOffset / verticesStride; + indices[indicesOffset++] = verticesIndex; + indices[indicesOffset++] = verticesIndex + 1; + indices[indicesOffset++] = verticesIndex + 2; + } + }; + + "use strict"; + const buildMap$1 = { + rectangle: buildRectangle, + polygon: buildPolygon, + triangle: buildTriangle, + circle: buildCircle, + ellipse: buildCircle, + roundedRectangle: buildCircle + }; + const tempRect$1 = new Rectangle(); + function buildContextBatches(context, gpuContext) { + const { geometryData, batches } = gpuContext; + batches.length = 0; + geometryData.indices.length = 0; + geometryData.vertices.length = 0; + geometryData.uvs.length = 0; + for (let i = 0; i < context.instructions.length; i++) { + const instruction = context.instructions[i]; + if (instruction.action === "texture") { + addTextureToGeometryData(instruction.data, batches, geometryData); + } else if (instruction.action === "fill" || instruction.action === "stroke") { + const isStroke = instruction.action === "stroke"; + const shapePath = instruction.data.path.shapePath; + const style = instruction.data.style; + const hole = instruction.data.hole; + if (isStroke && hole) { + addShapePathToGeometryData(hole.shapePath, style, null, true, batches, geometryData); + } + addShapePathToGeometryData(shapePath, style, hole, isStroke, batches, geometryData); + } + } + } + function addTextureToGeometryData(data, batches, geometryData) { + const { vertices, uvs, indices } = geometryData; + const indexOffset = indices.length; + const vertOffset = vertices.length / 2; + const points = []; + const build = buildMap$1.rectangle; + const rect = tempRect$1; + const texture = data.image; + rect.x = data.dx; + rect.y = data.dy; + rect.width = data.dw; + rect.height = data.dh; + const matrix = data.transform; + build.build(rect, points); + if (matrix) { + transformVertices(points, matrix); + } + build.triangulate(points, vertices, 2, vertOffset, indices, indexOffset); + const textureUvs = texture.uvs; + uvs.push( + textureUvs.x0, + textureUvs.y0, + textureUvs.x1, + textureUvs.y1, + textureUvs.x3, + textureUvs.y3, + textureUvs.x2, + textureUvs.y2 + ); + const graphicsBatch = BigPool.get(BatchableGraphics); + graphicsBatch.indexOffset = indexOffset; + graphicsBatch.indexSize = indices.length - indexOffset; + graphicsBatch.vertexOffset = vertOffset; + graphicsBatch.vertexSize = vertices.length / 2 - vertOffset; + graphicsBatch.color = data.style; + graphicsBatch.alpha = data.alpha; + graphicsBatch.texture = texture; + graphicsBatch.geometryData = geometryData; + batches.push(graphicsBatch); + } + function addShapePathToGeometryData(shapePath, style, hole, isStroke, batches, geometryData) { + const { vertices, uvs, indices } = geometryData; + const lastIndex = shapePath.shapePrimitives.length - 1; + shapePath.shapePrimitives.forEach(({ shape, transform: matrix }, i) => { + var _a; + const indexOffset = indices.length; + const vertOffset = vertices.length / 2; + const points = []; + const build = buildMap$1[shape.type]; + build.build(shape, points); + if (matrix) { + transformVertices(points, matrix); + } + if (!isStroke) { + if (hole && lastIndex === i) { + if (lastIndex !== 0) { + console.warn("[Pixi Graphics] only the last shape have be cut out"); + } + const holeIndices = []; + const otherPoints = points.slice(); + const holeArrays = getHoleArrays(hole.shapePath); + holeArrays.forEach((holePoints) => { + holeIndices.push(otherPoints.length / 2); + otherPoints.push(...holePoints); + }); + triangulateWithHoles(otherPoints, holeIndices, vertices, 2, vertOffset, indices, indexOffset); + } else { + build.triangulate(points, vertices, 2, vertOffset, indices, indexOffset); + } + } else { + const close = (_a = shape.closePath) != null ? _a : true; + const lineStyle = style; + buildLine(points, lineStyle, false, close, vertices, 2, vertOffset, indices, indexOffset); + } + const uvsOffset = uvs.length / 2; + const texture = style.texture; + if (texture !== Texture.WHITE) { + const textureMatrix = style.matrix; + if (matrix && textureMatrix) { + textureMatrix.append(matrix.clone().invert()); + } + buildUvs(vertices, 2, vertOffset, uvs, uvsOffset, 2, vertices.length / 2 - vertOffset, textureMatrix); + } else { + buildSimpleUvs(uvs, uvsOffset, 2, vertices.length / 2 - vertOffset); + } + const graphicsBatch = BigPool.get(BatchableGraphics); + graphicsBatch.indexOffset = indexOffset; + graphicsBatch.indexSize = indices.length - indexOffset; + graphicsBatch.vertexOffset = vertOffset; + graphicsBatch.vertexSize = vertices.length / 2 - vertOffset; + graphicsBatch.color = style.color; + graphicsBatch.alpha = style.alpha; + graphicsBatch.texture = texture; + graphicsBatch.geometryData = geometryData; + batches.push(graphicsBatch); + }); + } + function getHoleArrays(shape) { + if (!shape) + return []; + const holePrimitives = shape.shapePrimitives; + const holeArrays = []; + for (let k = 0; k < holePrimitives.length; k++) { + const holePrimitive = holePrimitives[k].shape; + const holePoints = []; + const holeBuilder = buildMap$1[holePrimitive.type]; + holeBuilder.build(holePrimitive, holePoints); + holeArrays.push(holePoints); + } + return holeArrays; + } + + "use strict"; + class GpuGraphicsContext { + constructor() { + this.batches = []; + this.geometryData = { + vertices: [], + uvs: [], + indices: [] + }; + } + } + class GraphicsContextRenderData { + constructor() { + this.geometry = new BatchGeometry(); + this.instructions = new InstructionSet(); + } + init() { + this.instructions.reset(); + } + } + const _GraphicsContextSystem = class _GraphicsContextSystem { + constructor() { + // the root context batches, used to either make a batch or geometry + // all graphics use this as a base + this._activeBatchers = []; + this._gpuContextHash = {}; + // used for non-batchable graphics + this._graphicsDataContextHash = /* @__PURE__ */ Object.create(null); + } + /** + * Runner init called, update the default options + * @ignore + */ + init(options) { + var _a; + _GraphicsContextSystem.defaultOptions.bezierSmoothness = (_a = options == null ? void 0 : options.bezierSmoothness) != null ? _a : _GraphicsContextSystem.defaultOptions.bezierSmoothness; + } + prerender() { + this._returnActiveBatchers(); + } + getContextRenderData(context) { + return this._graphicsDataContextHash[context.uid] || this._initContextRenderData(context); + } + // Context management functions + updateGpuContext(context) { + let gpuContext = this._gpuContextHash[context.uid] || this._initContext(context); + if (context.dirty) { + if (gpuContext) { + this._cleanGraphicsContextData(context); + } else { + gpuContext = this._initContext(context); + } + buildContextBatches(context, gpuContext); + const batchMode = context.batchMode; + if (context.customShader || batchMode === "no-batch") { + gpuContext.isBatchable = false; + } else if (batchMode === "auto") { + gpuContext.isBatchable = gpuContext.geometryData.vertices.length < 400; + } + context.dirty = false; + } + return gpuContext; + } + getGpuContext(context) { + return this._gpuContextHash[context.uid] || this._initContext(context); + } + _returnActiveBatchers() { + for (let i = 0; i < this._activeBatchers.length; i++) { + BigPool.return(this._activeBatchers[i]); + } + this._activeBatchers.length = 0; + } + _initContextRenderData(context) { + const graphicsData = BigPool.get(GraphicsContextRenderData); + const { batches, geometryData } = this._gpuContextHash[context.uid]; + const vertexSize = geometryData.vertices.length; + const indexSize = geometryData.indices.length; + for (let i = 0; i < batches.length; i++) { + batches[i].applyTransform = false; + } + const batcher = BigPool.get(Batcher); + this._activeBatchers.push(batcher); + batcher.ensureAttributeBuffer(vertexSize); + batcher.ensureIndexBuffer(indexSize); + batcher.begin(); + for (let i = 0; i < batches.length; i++) { + const batch = batches[i]; + batcher.add(batch); + } + batcher.finish(graphicsData.instructions); + const geometry = graphicsData.geometry; + geometry.indexBuffer.setDataWithSize(batcher.indexBuffer, batcher.indexSize, true); + geometry.buffers[0].setDataWithSize(batcher.attributeBuffer.float32View, batcher.attributeSize, true); + const drawBatches = batcher.batches; + for (let i = 0; i < drawBatches.length; i++) { + const batch = drawBatches[i]; + batch.bindGroup = getTextureBatchBindGroup(batch.textures.textures, batch.textures.count); + } + this._graphicsDataContextHash[context.uid] = graphicsData; + return graphicsData; + } + _initContext(context) { + const gpuContext = new GpuGraphicsContext(); + gpuContext.context = context; + this._gpuContextHash[context.uid] = gpuContext; + context.on("destroy", this.onGraphicsContextDestroy, this); + return this._gpuContextHash[context.uid]; + } + onGraphicsContextDestroy(context) { + this._cleanGraphicsContextData(context); + context.off("destroy", this.onGraphicsContextDestroy, this); + this._gpuContextHash[context.uid] = null; + } + _cleanGraphicsContextData(context) { + const gpuContext = this._gpuContextHash[context.uid]; + if (!gpuContext.isBatchable) { + if (this._graphicsDataContextHash[context.uid]) { + BigPool.return(this.getContextRenderData(context)); + this._graphicsDataContextHash[context.uid] = null; + } + } + if (gpuContext.batches) { + gpuContext.batches.forEach((batch) => { + BigPool.return(batch); + }); + } + } + destroy() { + for (const i in this._gpuContextHash) { + if (this._gpuContextHash[i]) { + this.onGraphicsContextDestroy(this._gpuContextHash[i].context); + } + } + } + }; + /** @ignore */ + _GraphicsContextSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "graphicsContext" + }; + /** The default options for the GraphicsContextSystem. */ + _GraphicsContextSystem.defaultOptions = { + /** + * A value from 0 to 1 that controls the smoothness of bezier curves (the higher the smoother) + * @default 0.5 + */ + bezierSmoothness: 0.5 + }; + let GraphicsContextSystem = _GraphicsContextSystem; + + "use strict"; + const blendModeIds = { + normal: 0, + add: 1, + multiply: 2, + screen: 3, + overlay: 4, + erase: 5, + "normal-npm": 6, + "add-npm": 7, + "screen-npm": 8 + }; + const BLEND$1 = 0; + const OFFSET$1 = 1; + const CULLING$1 = 2; + const DEPTH_TEST$1 = 3; + const WINDING$1 = 4; + const DEPTH_MASK$1 = 5; + const _State = class _State { + constructor() { + this.data = 0; + this.blendMode = "normal"; + this.polygonOffset = 0; + this.blend = true; + this.depthMask = true; + } + /** + * Activates blending of the computed fragment color values. + * @default true + */ + get blend() { + return !!(this.data & 1 << BLEND$1); + } + set blend(value) { + if (!!(this.data & 1 << BLEND$1) !== value) { + this.data ^= 1 << BLEND$1; + } + } + /** + * Activates adding an offset to depth values of polygon's fragments + * @default false + */ + get offsets() { + return !!(this.data & 1 << OFFSET$1); + } + set offsets(value) { + if (!!(this.data & 1 << OFFSET$1) !== value) { + this.data ^= 1 << OFFSET$1; + } + } + /** The culling settings for this state none - No culling back - Back face culling front - Front face culling */ + set cullMode(value) { + if (value === "none") { + this.culling = false; + return; + } + this.culling = true; + this.clockwiseFrontFace = value === "front"; + } + get cullMode() { + if (!this.culling) { + return "none"; + } + return this.clockwiseFrontFace ? "front" : "back"; + } + /** + * Activates culling of polygons. + * @default false + */ + get culling() { + return !!(this.data & 1 << CULLING$1); + } + set culling(value) { + if (!!(this.data & 1 << CULLING$1) !== value) { + this.data ^= 1 << CULLING$1; + } + } + /** + * Activates depth comparisons and updates to the depth buffer. + * @default false + */ + get depthTest() { + return !!(this.data & 1 << DEPTH_TEST$1); + } + set depthTest(value) { + if (!!(this.data & 1 << DEPTH_TEST$1) !== value) { + this.data ^= 1 << DEPTH_TEST$1; + } + } + /** + * Enables or disables writing to the depth buffer. + * @default true + */ + get depthMask() { + return !!(this.data & 1 << DEPTH_MASK$1); + } + set depthMask(value) { + if (!!(this.data & 1 << DEPTH_MASK$1) !== value) { + this.data ^= 1 << DEPTH_MASK$1; + } + } + /** + * Specifies whether or not front or back-facing polygons can be culled. + * @default false + */ + get clockwiseFrontFace() { + return !!(this.data & 1 << WINDING$1); + } + set clockwiseFrontFace(value) { + if (!!(this.data & 1 << WINDING$1) !== value) { + this.data ^= 1 << WINDING$1; + } + } + /** + * The blend mode to be applied when this state is set. Apply a value of `normal` to reset the blend mode. + * Setting this mode to anything other than NO_BLEND will automatically switch blending on. + * @default 'normal' + */ + get blendMode() { + return this._blendMode; + } + set blendMode(value) { + this.blend = value !== "none"; + this._blendMode = value; + this._blendModeId = blendModeIds[value] || 0; + } + /** + * The polygon offset. Setting this property to anything other than 0 will automatically enable polygon offset fill. + * @default 0 + */ + get polygonOffset() { + return this._polygonOffset; + } + set polygonOffset(value) { + this.offsets = !!value; + this._polygonOffset = value; + } + toString() { + return `[pixi.js/core:State blendMode=${this.blendMode} clockwiseFrontFace=${this.clockwiseFrontFace} culling=${this.culling} depthMask=${this.depthMask} polygonOffset=${this.polygonOffset}]`; + } + /** + * A quickly getting an instance of a State that is configured for 2d rendering. + * @returns a new State with values set for 2d rendering + */ + static for2d() { + const state = new _State(); + state.depthTest = false; + state.blend = true; + return state; + } + }; + _State.default2d = _State.for2d(); + let State = _State; + + "use strict"; + function colorToUniform(rgb, alpha, out, offset) { + out[offset++] = (rgb >> 16 & 255) / 255; + out[offset++] = (rgb >> 8 & 255) / 255; + out[offset++] = (rgb & 255) / 255; + out[offset++] = alpha; + } + function color32BitToUniform(abgr, out, offset) { + const alpha = (abgr >> 24 & 255) / 255; + out[offset++] = (abgr & 255) / 255 * alpha; + out[offset++] = (abgr >> 8 & 255) / 255 * alpha; + out[offset++] = (abgr >> 16 & 255) / 255 * alpha; + out[offset++] = alpha; + } + + "use strict"; + class GraphicsPipe { + constructor(renderer, adaptor) { + this.state = State.for2d(); + // batchable graphics list, used to render batches + this._graphicsBatchesHash = /* @__PURE__ */ Object.create(null); + this.renderer = renderer; + this._adaptor = adaptor; + this._adaptor.init(); + } + validateRenderable(graphics) { + const context = graphics.context; + const wasBatched = !!this._graphicsBatchesHash[graphics.uid]; + const gpuContext = this.renderer.graphicsContext.updateGpuContext(context); + if (gpuContext.isBatchable || wasBatched !== gpuContext.isBatchable) { + return true; + } + return false; + } + addRenderable(graphics, instructionSet) { + const gpuContext = this.renderer.graphicsContext.updateGpuContext(graphics.context); + if (graphics._didGraphicsUpdate) { + graphics._didGraphicsUpdate = false; + this._rebuild(graphics); + } + if (gpuContext.isBatchable) { + this._addToBatcher(graphics, instructionSet); + } else { + this.renderer.renderPipes.batch.break(instructionSet); + instructionSet.add(graphics); + } + } + updateRenderable(graphics) { + const batches = this._graphicsBatchesHash[graphics.uid]; + if (batches) { + for (let i = 0; i < batches.length; i++) { + const batch = batches[i]; + batch.batcher.updateElement(batch); + } + } + } + destroyRenderable(graphics) { + if (this._graphicsBatchesHash[graphics.uid]) { + this._removeBatchForRenderable(graphics.uid); + } + } + execute(graphics) { + if (!graphics.isRenderable) + return; + const renderer = this.renderer; + const context = graphics.context; + const contextSystem = renderer.graphicsContext; + if (!contextSystem.getGpuContext(context).batches.length) { + return; + } + const shader = context.customShader || this._adaptor.shader; + this.state.blendMode = graphics.groupBlendMode; + const localUniforms = shader.resources.localUniforms.uniforms; + localUniforms.uTransformMatrix = graphics.groupTransform; + localUniforms.uRound = renderer._roundPixels | graphics._roundPixels; + color32BitToUniform( + graphics.groupColorAlpha, + localUniforms.uColor, + 0 + ); + this._adaptor.execute(this, graphics); + } + _rebuild(graphics) { + const wasBatched = !!this._graphicsBatchesHash[graphics.uid]; + const gpuContext = this.renderer.graphicsContext.updateGpuContext(graphics.context); + if (wasBatched) { + this._removeBatchForRenderable(graphics.uid); + } + if (gpuContext.isBatchable) { + this._initBatchesForRenderable(graphics); + } + graphics.batched = gpuContext.isBatchable; + } + _addToBatcher(graphics, instructionSet) { + const batchPipe = this.renderer.renderPipes.batch; + const batches = this._getBatchesForRenderable(graphics); + for (let i = 0; i < batches.length; i++) { + const batch = batches[i]; + batchPipe.addToBatch(batch, instructionSet); + } + } + _getBatchesForRenderable(graphics) { + return this._graphicsBatchesHash[graphics.uid] || this._initBatchesForRenderable(graphics); + } + _initBatchesForRenderable(graphics) { + const context = graphics.context; + const gpuContext = this.renderer.graphicsContext.getGpuContext(context); + const roundPixels = this.renderer._roundPixels | graphics._roundPixels; + const batches = gpuContext.batches.map((batch) => { + const batchClone = BigPool.get(BatchableGraphics); + batch.copyTo(batchClone); + batchClone.renderable = graphics; + batchClone.roundPixels = roundPixels; + return batchClone; + }); + if (this._graphicsBatchesHash[graphics.uid] === void 0) { + graphics.on("destroyed", () => { + this.destroyRenderable(graphics); + }); + } + this._graphicsBatchesHash[graphics.uid] = batches; + return batches; + } + _removeBatchForRenderable(graphicsUid) { + this._graphicsBatchesHash[graphicsUid].forEach((batch) => { + BigPool.return(batch); + }); + this._graphicsBatchesHash[graphicsUid] = null; + } + destroy() { + this.renderer = null; + this._adaptor.destroy(); + this._adaptor = null; + this.state = null; + for (const i in this._graphicsBatchesHash) { + this._removeBatchForRenderable(i); + } + this._graphicsBatchesHash = null; + } + } + /** @ignore */ + GraphicsPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "graphics" + }; + + "use strict"; + extensions.add(GraphicsPipe); + extensions.add(GraphicsContextSystem); + + "use strict"; + const idCounts = /* @__PURE__ */ Object.create(null); + const idHash = /* @__PURE__ */ Object.create(null); + function createIdFromString(value, groupId) { + let id = idHash[value]; + if (id === void 0) { + if (idCounts[groupId] === void 0) { + idCounts[groupId] = 1; + } + idHash[value] = id = idCounts[groupId]++; + } + return id; + } + + "use strict"; + const UNIFORM_TYPES_VALUES = [ + "f32", + "i32", + "vec2", + "vec3", + "vec4", + "mat2x2", + "mat3x3", + "mat4x4", + "mat3x2", + "mat4x2", + "mat2x3", + "mat4x3", + "mat2x4", + "mat3x4" + ]; + const UNIFORM_TYPES_MAP = UNIFORM_TYPES_VALUES.reduce((acc, type) => { + acc[type] = true; + return acc; + }, {}); + + "use strict"; + function getDefaultUniformValue(type, size) { + switch (type) { + case "f32": + return 0; + case "vec2": + return new Float32Array(2 * size); + case "vec3": + return new Float32Array(3 * size); + case "vec4": + return new Float32Array(4 * size); + case "mat2x2": + return new Float32Array([ + 1, + 0, + 0, + 1 + ]); + case "mat3x3": + return new Float32Array([ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ]); + case "mat4x4": + return new Float32Array([ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ]); + } + return null; + } + + "use strict"; + var __defProp$T = Object.defineProperty; + var __getOwnPropSymbols$T = Object.getOwnPropertySymbols; + var __hasOwnProp$T = Object.prototype.hasOwnProperty; + var __propIsEnum$T = Object.prototype.propertyIsEnumerable; + var __defNormalProp$T = (obj, key, value) => key in obj ? __defProp$T(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$T = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$T.call(b, prop)) + __defNormalProp$T(a, prop, b[prop]); + if (__getOwnPropSymbols$T) + for (var prop of __getOwnPropSymbols$T(b)) { + if (__propIsEnum$T.call(b, prop)) + __defNormalProp$T(a, prop, b[prop]); + } + return a; + }; + const _UniformGroup = class _UniformGroup { + /** + * Create a new Uniform group + * @param uniformStructures - The structures of the uniform group + * @param options - The optional parameters of this uniform group + */ + constructor(uniformStructures, options) { + /** used internally to know if a uniform group was used in the last render pass */ + this._touched = 0; + /** a unique id for this uniform group used through the renderer */ + this.uid = uid("uniform"); + /** a resource type, used to identify how to handle it when its in a bind group / shader resource */ + this._resourceType = "uniformGroup"; + /** the resource id used internally by the renderer to build bind group keys */ + this._resourceId = uid("resource"); + /** used ito identify if this is a uniform group */ + this.isUniformGroup = true; + /** + * used to flag if this Uniform groups data is different from what it has stored in its buffer / on the GPU + * @internal + * @ignore + */ + this._dirtyId = 0; + // implementing the interface - UniformGroup are not destroyed + this.destroyed = false; + var _a, _b; + options = __spreadValues$T(__spreadValues$T({}, _UniformGroup.defaultOptions), options); + this.uniformStructures = uniformStructures; + const uniforms = {}; + for (const i in uniformStructures) { + const uniformData = uniformStructures[i]; + uniformData.name = i; + uniformData.size = (_a = uniformData.size) != null ? _a : 1; + if (!UNIFORM_TYPES_MAP[uniformData.type]) { + throw new Error(`Uniform type ${uniformData.type} is not supported. Supported uniform types are: ${UNIFORM_TYPES_VALUES.join(", ")}`); + } + (_b = uniformData.value) != null ? _b : uniformData.value = getDefaultUniformValue(uniformData.type, uniformData.size); + uniforms[i] = uniformData.value; + } + this.uniforms = uniforms; + this._dirtyId = 1; + this.ubo = options.ubo; + this.isStatic = options.isStatic; + this._signature = createIdFromString(Object.keys(uniforms).map( + (i) => `${i}-${uniformStructures[i].type}` + ).join("-"), "uniform-group"); + } + /** Call this if you want the uniform groups data to be uploaded to the GPU only useful if `isStatic` is true. */ + update() { + this._dirtyId++; + } + }; + /** The default options used by the uniform group. */ + _UniformGroup.defaultOptions = { + /** if true the UniformGroup is handled as an Uniform buffer object. */ + ubo: false, + /** if true, then you are responsible for when the data is uploaded to the GPU by calling `update()` */ + isStatic: false + }; + let UniformGroup = _UniformGroup; + + "use strict"; + class BatchableMesh { + constructor() { + this.batcher = null; + this.batch = null; + this.roundPixels = 0; + this._uvUpdateId = -1; + this._textureMatrixUpdateId = -1; + } + get blendMode() { + return this.mesh.groupBlendMode; + } + reset() { + this.mesh = null; + this.texture = null; + this.batcher = null; + this.batch = null; + } + packIndex(indexBuffer, index, indicesOffset) { + const indices = this.geometry.indices; + for (let i = 0; i < indices.length; i++) { + indexBuffer[index++] = indices[i] + indicesOffset; + } + } + packAttributes(float32View, uint32View, index, textureId) { + const mesh = this.mesh; + const geometry = this.geometry; + const wt = mesh.groupTransform; + const textureIdAndRound = textureId << 16 | this.roundPixels & 65535; + const a = wt.a; + const b = wt.b; + const c = wt.c; + const d = wt.d; + const tx = wt.tx; + const ty = wt.ty; + const positions = geometry.positions; + const uvBuffer = geometry.getBuffer("aUV"); + const uvs = uvBuffer.data; + let transformedUvs = uvs; + const textureMatrix = this.texture.textureMatrix; + if (!textureMatrix.isSimple) { + transformedUvs = this._transformedUvs; + if (this._textureMatrixUpdateId !== textureMatrix._updateID || this._uvUpdateId !== uvBuffer._updateID) { + if (!transformedUvs || transformedUvs.length < uvs.length) { + transformedUvs = this._transformedUvs = new Float32Array(uvs.length); + } + this._textureMatrixUpdateId = textureMatrix._updateID; + this._uvUpdateId = uvBuffer._updateID; + textureMatrix.multiplyUvs(uvs, transformedUvs); + } + } + const abgr = mesh.groupColorAlpha; + for (let i = 0; i < positions.length; i += 2) { + const x = positions[i]; + const y = positions[i + 1]; + float32View[index] = a * x + c * y + tx; + float32View[index + 1] = b * x + d * y + ty; + float32View[index + 2] = transformedUvs[i]; + float32View[index + 3] = transformedUvs[i + 1]; + uint32View[index + 4] = abgr; + uint32View[index + 5] = textureIdAndRound; + index += 6; + } + } + get vertexSize() { + return this.geometry.positions.length / 2; + } + get indexSize() { + return this.geometry.indices.length; + } + } + + "use strict"; + class MeshPipe { + constructor(renderer, adaptor) { + this.localUniforms = new UniformGroup({ + uTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4" }, + uRound: { value: 0, type: "f32" } + }); + this.localUniformsBindGroup = new BindGroup({ + 0: this.localUniforms + }); + this._meshDataHash = /* @__PURE__ */ Object.create(null); + this._gpuBatchableMeshHash = /* @__PURE__ */ Object.create(null); + this.renderer = renderer; + this._adaptor = adaptor; + this._adaptor.init(); + } + validateRenderable(mesh) { + const meshData = this._getMeshData(mesh); + const wasBatched = meshData.batched; + const isBatched = mesh.batched; + meshData.batched = isBatched; + if (wasBatched !== isBatched) { + return true; + } else if (isBatched) { + const geometry = mesh._geometry; + if (geometry.indices.length !== meshData.indexSize || geometry.positions.length !== meshData.vertexSize) { + meshData.indexSize = geometry.indices.length; + meshData.vertexSize = geometry.positions.length; + return true; + } + const batchableMesh = this._getBatchableMesh(mesh); + const texture = mesh.texture; + if (batchableMesh.texture._source !== texture._source) { + if (batchableMesh.texture._source !== texture._source) { + return !batchableMesh.batcher.checkAndUpdateTexture(batchableMesh, texture); + } + } + } + return false; + } + addRenderable(mesh, instructionSet) { + const batcher = this.renderer.renderPipes.batch; + const { batched } = this._getMeshData(mesh); + if (batched) { + const gpuBatchableMesh = this._getBatchableMesh(mesh); + gpuBatchableMesh.texture = mesh._texture; + gpuBatchableMesh.geometry = mesh._geometry; + batcher.addToBatch(gpuBatchableMesh); + } else { + batcher.break(instructionSet); + instructionSet.add({ + renderPipeId: "mesh", + mesh + }); + } + } + updateRenderable(mesh) { + if (mesh.batched) { + const gpuBatchableMesh = this._gpuBatchableMeshHash[mesh.uid]; + gpuBatchableMesh.texture = mesh._texture; + gpuBatchableMesh.geometry = mesh._geometry; + gpuBatchableMesh.batcher.updateElement(gpuBatchableMesh); + } + } + destroyRenderable(mesh) { + this._meshDataHash[mesh.uid] = null; + const gpuMesh = this._gpuBatchableMeshHash[mesh.uid]; + if (gpuMesh) { + BigPool.return(gpuMesh); + this._gpuBatchableMeshHash[mesh.uid] = null; + } + } + execute({ mesh }) { + if (!mesh.isRenderable) + return; + mesh.state.blendMode = mesh.groupBlendMode; + const localUniforms = this.localUniforms; + localUniforms.uniforms.uTransformMatrix = mesh.groupTransform; + localUniforms.uniforms.uRound = this.renderer._roundPixels | mesh._roundPixels; + localUniforms.update(); + color32BitToUniform( + mesh.groupColorAlpha, + localUniforms.uniforms.uColor, + 0 + ); + this._adaptor.execute(this, mesh); + } + _getMeshData(mesh) { + return this._meshDataHash[mesh.uid] || this._initMeshData(mesh); + } + _initMeshData(mesh) { + var _a, _b; + this._meshDataHash[mesh.uid] = { + batched: mesh.batched, + indexSize: (_a = mesh._geometry.indices) == null ? void 0 : _a.length, + vertexSize: (_b = mesh._geometry.positions) == null ? void 0 : _b.length + }; + mesh.on("destroyed", () => { + this.destroyRenderable(mesh); + }); + return this._meshDataHash[mesh.uid]; + } + _getBatchableMesh(mesh) { + return this._gpuBatchableMeshHash[mesh.uid] || this._initBatchableMesh(mesh); + } + _initBatchableMesh(mesh) { + const gpuMesh = BigPool.get(BatchableMesh); + gpuMesh.mesh = mesh; + gpuMesh.texture = mesh._texture; + gpuMesh.roundPixels = this.renderer._roundPixels | mesh._roundPixels; + this._gpuBatchableMeshHash[mesh.uid] = gpuMesh; + gpuMesh.mesh = mesh; + return gpuMesh; + } + destroy() { + for (const i in this._gpuBatchableMeshHash) { + if (this._gpuBatchableMeshHash[i]) { + BigPool.return(this._gpuBatchableMeshHash[i]); + } + } + this._gpuBatchableMeshHash = null; + this._meshDataHash = null; + this.localUniforms = null; + this.localUniformsBindGroup = null; + this._adaptor.destroy(); + this._adaptor = null; + this.renderer = null; + } + } + /** @ignore */ + MeshPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "mesh" + }; + + "use strict"; + extensions.add(MeshPipe); + + "use strict"; + class BatchableSprite { + constructor() { + // batch specific.. + this.vertexSize = 4; + this.indexSize = 6; + this.location = 0; + // location in the buffer + this.batcher = null; + this.batch = null; + this.roundPixels = 0; + } + get blendMode() { + return this.renderable.groupBlendMode; + } + packAttributes(float32View, uint32View, index, textureId) { + const sprite = this.renderable; + const texture = this.texture; + const wt = sprite.groupTransform; + const a = wt.a; + const b = wt.b; + const c = wt.c; + const d = wt.d; + const tx = wt.tx; + const ty = wt.ty; + const bounds = this.bounds; + const w0 = bounds.maxX; + const w1 = bounds.minX; + const h0 = bounds.maxY; + const h1 = bounds.minY; + const uvs = texture.uvs; + const argb = sprite.groupColorAlpha; + const textureIdAndRound = textureId << 16 | this.roundPixels & 65535; + float32View[index + 0] = a * w1 + c * h1 + tx; + float32View[index + 1] = d * h1 + b * w1 + ty; + float32View[index + 2] = uvs.x0; + float32View[index + 3] = uvs.y0; + uint32View[index + 4] = argb; + uint32View[index + 5] = textureIdAndRound; + float32View[index + 6] = a * w0 + c * h1 + tx; + float32View[index + 7] = d * h1 + b * w0 + ty; + float32View[index + 8] = uvs.x1; + float32View[index + 9] = uvs.y1; + uint32View[index + 10] = argb; + uint32View[index + 11] = textureIdAndRound; + float32View[index + 12] = a * w0 + c * h0 + tx; + float32View[index + 13] = d * h0 + b * w0 + ty; + float32View[index + 14] = uvs.x2; + float32View[index + 15] = uvs.y2; + uint32View[index + 16] = argb; + uint32View[index + 17] = textureIdAndRound; + float32View[index + 18] = a * w1 + c * h0 + tx; + float32View[index + 19] = d * h0 + b * w1 + ty; + float32View[index + 20] = uvs.x3; + float32View[index + 21] = uvs.y3; + uint32View[index + 22] = argb; + uint32View[index + 23] = textureIdAndRound; + } + packIndex(indexBuffer, index, indicesOffset) { + indexBuffer[index] = indicesOffset + 0; + indexBuffer[index + 1] = indicesOffset + 1; + indexBuffer[index + 2] = indicesOffset + 2; + indexBuffer[index + 3] = indicesOffset + 0; + indexBuffer[index + 4] = indicesOffset + 2; + indexBuffer[index + 5] = indicesOffset + 3; + } + reset() { + this.renderable = null; + this.texture = null; + this.batcher = null; + this.batch = null; + this.bounds = null; + } + } + + "use strict"; + class CanvasTextPipe { + constructor(renderer) { + this._gpuText = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + validateRenderable(text) { + var _a; + const gpuText = this._getGpuText(text); + const newKey = text._getKey(); + if (gpuText.currentKey !== newKey) { + const resolution = (_a = text.resolution) != null ? _a : this._renderer.resolution; + const { width, height } = this._renderer.canvasText.getTextureSize( + text.text, + resolution, + text._style + ); + if ( + // is only being used by this text: + this._renderer.canvasText.getReferenceCount(gpuText.currentKey) === 1 && width === gpuText.texture._source.width && height === gpuText.texture._source.height + ) { + return false; + } + return true; + } + return false; + } + addRenderable(text, _instructionSet) { + const gpuText = this._getGpuText(text); + const batchableSprite = gpuText.batchableSprite; + if (text._didTextUpdate) { + this._updateText(text); + } + this._renderer.renderPipes.batch.addToBatch(batchableSprite); + } + updateRenderable(text) { + const gpuText = this._getGpuText(text); + const batchableSprite = gpuText.batchableSprite; + if (text._didTextUpdate) { + this._updateText(text); + } + batchableSprite.batcher.updateElement(batchableSprite); + } + destroyRenderable(text) { + this._destroyRenderableById(text.uid); + } + _destroyRenderableById(textUid) { + const gpuText = this._gpuText[textUid]; + this._renderer.canvasText.decreaseReferenceCount(gpuText.currentKey); + BigPool.return(gpuText.batchableSprite); + this._gpuText[textUid] = null; + } + _updateText(text) { + const newKey = text._getKey(); + const gpuText = this._getGpuText(text); + const batchableSprite = gpuText.batchableSprite; + if (gpuText.currentKey !== newKey) { + this._updateGpuText(text); + } + text._didTextUpdate = false; + const padding = text._style.padding; + updateQuadBounds(batchableSprite.bounds, text._anchor, batchableSprite.texture, padding); + } + _updateGpuText(text) { + const gpuText = this._getGpuText(text); + const batchableSprite = gpuText.batchableSprite; + if (gpuText.texture) { + this._renderer.canvasText.decreaseReferenceCount(gpuText.currentKey); + } + gpuText.texture = batchableSprite.texture = this._renderer.canvasText.getManagedTexture(text); + gpuText.currentKey = text._getKey(); + batchableSprite.texture = gpuText.texture; + } + _getGpuText(text) { + return this._gpuText[text.uid] || this.initGpuText(text); + } + initGpuText(text) { + const gpuTextData = { + texture: null, + currentKey: "--", + batchableSprite: BigPool.get(BatchableSprite) + }; + gpuTextData.batchableSprite.renderable = text; + gpuTextData.batchableSprite.bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 }; + gpuTextData.batchableSprite.roundPixels = this._renderer._roundPixels | text._roundPixels; + this._gpuText[text.uid] = gpuTextData; + this._updateText(text); + text.on("destroyed", () => { + this.destroyRenderable(text); + }); + return gpuTextData; + } + destroy() { + for (const i in this._gpuText) { + this._destroyRenderableById(i); + } + this._gpuText = null; + this._renderer = null; + } + } + /** @ignore */ + CanvasTextPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "text" + }; + + "use strict"; + class CanvasPoolClass { + constructor(canvasOptions) { + this._canvasPool = /* @__PURE__ */ Object.create(null); + this.canvasOptions = canvasOptions || {}; + this.enableFullScreen = false; + } + /** + * Creates texture with params that were specified in pool constructor. + * @param pixelWidth - Width of texture in pixels. + * @param pixelHeight - Height of texture in pixels. + */ + _createCanvasAndContext(pixelWidth, pixelHeight) { + const canvas = DOMAdapter.get().createCanvas(); + canvas.width = pixelWidth; + canvas.height = pixelHeight; + const context = canvas.getContext("2d"); + return { canvas, context }; + } + /** + * Gets a Power-of-Two render texture or fullScreen texture + * @param minWidth - The minimum width of the render texture. + * @param minHeight - The minimum height of the render texture. + * @param resolution - The resolution of the render texture. + * @returns The new render texture. + */ + getOptimalCanvasAndContext(minWidth, minHeight, resolution = 1) { + minWidth = Math.ceil(minWidth * resolution - 1e-6); + minHeight = Math.ceil(minHeight * resolution - 1e-6); + minWidth = nextPow2(minWidth); + minHeight = nextPow2(minHeight); + const key = (minWidth << 17) + (minHeight << 1); + if (!this._canvasPool[key]) { + this._canvasPool[key] = []; + } + let canvasAndContext = this._canvasPool[key].pop(); + if (!canvasAndContext) { + canvasAndContext = this._createCanvasAndContext(minWidth, minHeight); + } + return canvasAndContext; + } + /** + * Place a render texture back into the pool. + * @param canvasAndContext + */ + returnCanvasAndContext(canvasAndContext) { + const { width, height } = canvasAndContext.canvas; + const key = (width << 17) + (height << 1); + this._canvasPool[key].push(canvasAndContext); + } + clear() { + this._canvasPool = {}; + } + } + const CanvasPool = new CanvasPoolClass(); + + "use strict"; + var __defProp$S = Object.defineProperty; + var __defProps$k = Object.defineProperties; + var __getOwnPropDescs$k = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$S = Object.getOwnPropertySymbols; + var __hasOwnProp$S = Object.prototype.hasOwnProperty; + var __propIsEnum$S = Object.prototype.propertyIsEnumerable; + var __defNormalProp$S = (obj, key, value) => key in obj ? __defProp$S(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$S = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$S.call(b, prop)) + __defNormalProp$S(a, prop, b[prop]); + if (__getOwnPropSymbols$S) + for (var prop of __getOwnPropSymbols$S(b)) { + if (__propIsEnum$S.call(b, prop)) + __defNormalProp$S(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$k = (a, b) => __defProps$k(a, __getOwnPropDescs$k(b)); + let count = 0; + class TexturePoolClass { + /** + * @param textureOptions - options that will be passed to BaseRenderTexture constructor + * @param {SCALE_MODE} [textureOptions.scaleMode] - See {@link SCALE_MODE} for possible values. + */ + constructor(textureOptions) { + this._poolKeyHash = /* @__PURE__ */ Object.create(null); + this._texturePool = {}; + this.textureOptions = textureOptions || {}; + this.enableFullScreen = false; + } + /** + * Creates texture with params that were specified in pool constructor. + * @param pixelWidth - Width of texture in pixels. + * @param pixelHeight - Height of texture in pixels. + * @param antialias + */ + createTexture(pixelWidth, pixelHeight, antialias) { + const textureSource = new TextureSource(__spreadProps$k(__spreadValues$S({}, this.textureOptions), { + width: pixelWidth, + height: pixelHeight, + resolution: 1, + antialias, + autoGarbageCollect: true + })); + return new Texture({ + source: textureSource, + label: `texturePool_${count++}` + }); + } + /** + * Gets a Power-of-Two render texture or fullScreen texture + * @param frameWidth - The minimum width of the render texture. + * @param frameHeight - The minimum height of the render texture. + * @param resolution - The resolution of the render texture. + * @param antialias + * @returns The new render texture. + */ + getOptimalTexture(frameWidth, frameHeight, resolution = 1, antialias) { + let po2Width = Math.ceil(frameWidth * resolution - 1e-6); + let po2Height = Math.ceil(frameHeight * resolution - 1e-6); + po2Width = nextPow2(po2Width); + po2Height = nextPow2(po2Height); + const key = (po2Width << 17) + (po2Height << 1) + (antialias ? 1 : 0); + if (!this._texturePool[key]) { + this._texturePool[key] = []; + } + let texture = this._texturePool[key].pop(); + if (!texture) { + texture = this.createTexture(po2Width, po2Height, antialias); + } + texture.source._resolution = resolution; + texture.source.width = po2Width / resolution; + texture.source.height = po2Height / resolution; + texture.source.pixelWidth = po2Width; + texture.source.pixelHeight = po2Height; + texture.frame.x = 0; + texture.frame.y = 0; + texture.frame.width = frameWidth; + texture.frame.height = frameHeight; + texture.updateUvs(); + this._poolKeyHash[texture.uid] = key; + return texture; + } + /** + * Gets extra texture of the same size as input renderTexture + * @param texture - The texture to check what size it is. + * @param antialias - Whether to use antialias. + * @returns A texture that is a power of two + */ + getSameSizeTexture(texture, antialias = false) { + const source = texture.source; + return this.getOptimalTexture(texture.width, texture.height, source._resolution, antialias); + } + /** + * Place a render texture back into the pool. + * @param renderTexture - The renderTexture to free + */ + returnTexture(renderTexture) { + const key = this._poolKeyHash[renderTexture.uid]; + this._texturePool[key].push(renderTexture); + } + /** + * Clears the pool. + * @param destroyTextures - Destroy all stored textures. + */ + clear(destroyTextures) { + destroyTextures = destroyTextures !== false; + if (destroyTextures) { + for (const i in this._texturePool) { + const textures = this._texturePool[i]; + if (textures) { + for (let j = 0; j < textures.length; j++) { + textures[j].destroy(true); + } + } + } + } + this._texturePool = {}; + } + } + const TexturePool = new TexturePoolClass(); + + "use strict"; + function checkRow(data, width, y) { + for (let x = 0, index = 4 * y * width; x < width; ++x, index += 4) { + if (data[index + 3] !== 0) + return false; + } + return true; + } + function checkColumn(data, width, x, top, bottom) { + const stride = 4 * width; + for (let y = top, index = top * stride + 4 * x; y <= bottom; ++y, index += stride) { + if (data[index + 3] !== 0) + return false; + } + return true; + } + function getCanvasBoundingBox(canvas, resolution = 1) { + const { width, height } = canvas; + const context = canvas.getContext("2d", { + willReadFrequently: true + }); + if (context === null) { + throw new TypeError("Failed to get canvas 2D context"); + } + const imageData = context.getImageData(0, 0, width, height); + const data = imageData.data; + let left = 0; + let top = 0; + let right = width - 1; + let bottom = height - 1; + while (top < height && checkRow(data, width, top)) + ++top; + if (top === height) + return Rectangle.EMPTY; + while (checkRow(data, width, bottom)) + --bottom; + while (checkColumn(data, width, left, top, bottom)) + ++left; + while (checkColumn(data, width, right, top, bottom)) + --right; + ++right; + ++bottom; + return new Rectangle(left / resolution, top / resolution, (right - left) / resolution, (bottom - top) / resolution); + } + + "use strict"; + const _FillGradient = class _FillGradient { + constructor(x0, y0, x1, y1) { + this.uid = uid("fillGradient"); + this.type = "linear"; + this.gradientStops = []; + this._styleKey = null; + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + } + addColorStop(offset, color) { + this.gradientStops.push({ offset, color: Color.shared.setValue(color).toHex() }); + this._styleKey = null; + return this; + } + // TODO move to the system! + buildLinearGradient() { + const defaultSize = _FillGradient.defaultTextureSize; + const { gradientStops } = this; + const canvas = DOMAdapter.get().createCanvas(); + canvas.width = defaultSize; + canvas.height = defaultSize; + const ctx = canvas.getContext("2d"); + const gradient = ctx.createLinearGradient(0, 0, _FillGradient.defaultTextureSize, 1); + for (let i = 0; i < gradientStops.length; i++) { + const stop = gradientStops[i]; + gradient.addColorStop(stop.offset, stop.color); + } + ctx.fillStyle = gradient; + ctx.fillRect(0, 0, defaultSize, defaultSize); + this.texture = new Texture({ + source: new ImageSource({ + resource: canvas, + addressModeU: "clamp-to-edge", + addressModeV: "repeat" + }) + }); + const { x0, y0, x1, y1 } = this; + const m = new Matrix(); + const dx = x1 - x0; + const dy = y1 - y0; + const dist = Math.sqrt(dx * dx + dy * dy); + const angle = Math.atan2(dy, dx); + m.translate(-x0, -y0); + m.scale(1 / defaultSize, 1 / defaultSize); + m.rotate(-angle); + m.scale(256 / dist, 1); + this.transform = m; + this._styleKey = null; + } + get styleKey() { + if (this._styleKey) { + return this._styleKey; + } + const stops = this.gradientStops.map((stop) => `${stop.offset}-${stop.color}`).join("-"); + const texture = this.texture.uid; + const transform = this.transform.toArray().join("-"); + return `fill-gradient-${this.uid}-${stops}-${texture}-${transform}-${this.x0}-${this.y0}-${this.x1}-${this.y1}`; + } + }; + _FillGradient.defaultTextureSize = 256; + let FillGradient = _FillGradient; + + "use strict"; + const repetitionMap = { + repeat: { + addressModeU: "repeat", + addressModeV: "repeat" + }, + "repeat-x": { + addressModeU: "repeat", + addressModeV: "clamp-to-edge" + }, + "repeat-y": { + addressModeU: "clamp-to-edge", + addressModeV: "repeat" + }, + "no-repeat": { + addressModeU: "clamp-to-edge", + addressModeV: "clamp-to-edge" + } + }; + class FillPattern { + constructor(texture, repetition) { + this.uid = uid("fillPattern"); + this.transform = new Matrix(); + this._styleKey = null; + this.texture = texture; + this.transform.scale( + 1 / texture.frame.width, + 1 / texture.frame.height + ); + if (repetition) { + texture.source.style.addressModeU = repetitionMap[repetition].addressModeU; + texture.source.style.addressModeV = repetitionMap[repetition].addressModeV; + } + } + setTransform(transform) { + const texture = this.texture; + this.transform.copyFrom(transform); + this.transform.invert(); + this.transform.scale( + 1 / texture.frame.width, + 1 / texture.frame.height + ); + this._styleKey = null; + } + get styleKey() { + if (this._styleKey) + return this._styleKey; + this._styleKey = `fill-pattern-${this.uid}-${this.texture.uid}-${this.transform.toArray().join("-")}`; + return this._styleKey; + } + } + + var parseSvgPath = parse; + + /** + * expected argument lengths + * @type {Object} + */ + + var length = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0}; + + /** + * segment pattern + * @type {RegExp} + */ + + var segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig; + + /** + * parse an svg path data string. Generates an Array + * of commands where each command is an Array of the + * form `[command, arg1, arg2, ...]` + * + * @param {String} path + * @return {Array} + */ + + function parse(path) { + var data = []; + path.replace(segment, function(_, command, args){ + var type = command.toLowerCase(); + args = parseValues(args); + + // overloaded moveTo + if (type == 'm' && args.length > 2) { + data.push([command].concat(args.splice(0, 2))); + type = 'l'; + command = command == 'm' ? 'l' : 'L'; + } + + while (true) { + if (args.length == length[type]) { + args.unshift(command); + return data.push(args) + } + if (args.length < length[type]) throw new Error('malformed path data') + data.push([command].concat(args.splice(0, length[type]))); + } + }); + return data + } + + var number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig; + + function parseValues(args) { + var numbers = args.match(number); + return numbers ? numbers.map(Number) : [] + } + + var parse$1 = /*@__PURE__*/getDefaultExportFromCjs(parseSvgPath); + + "use strict"; + function SVGToGraphicsPath(svgPath, path) { + const commands = parse$1(svgPath); + const subpaths = []; + let currentSubPath = null; + let lastX = 0; + let lastY = 0; + for (let i = 0; i < commands.length; i++) { + const command = commands[i]; + const type = command[0]; + const data = command; + switch (type) { + case "M": + lastX = data[1]; + lastY = data[2]; + path.moveTo(lastX, lastY); + break; + case "m": + lastX += data[1]; + lastY += data[2]; + path.moveTo(lastX, lastY); + break; + case "H": + lastX = data[1]; + path.lineTo(lastX, lastY); + break; + case "h": + lastX += data[1]; + path.lineTo(lastX, lastY); + break; + case "V": + lastY = data[1]; + path.lineTo(lastX, lastY); + break; + case "v": + lastY += data[1]; + path.lineTo(lastX, lastY); + break; + case "L": + lastX = data[1]; + lastY = data[2]; + path.lineTo(lastX, lastY); + break; + case "l": + lastX += data[1]; + lastY += data[2]; + path.lineTo(lastX, lastY); + break; + case "C": + lastX = data[5]; + lastY = data[6]; + path.bezierCurveTo( + data[1], + data[2], + data[3], + data[4], + lastX, + lastY + ); + break; + case "c": + path.bezierCurveTo( + lastX + data[1], + lastY + data[2], + lastX + data[3], + lastY + data[4], + lastX + data[5], + lastY + data[6] + ); + lastX += data[5]; + lastY += data[6]; + break; + case "S": + lastX = data[3]; + lastY = data[4]; + path.bezierCurveToShort( + data[1], + data[2], + lastX, + lastY + ); + break; + case "s": + path.bezierCurveToShort( + lastX + data[1], + lastY + data[2], + lastX + data[3], + lastY + data[4] + ); + lastX += data[3]; + lastY += data[4]; + break; + case "Q": + lastX = data[3]; + lastY = data[4]; + path.quadraticCurveTo( + data[1], + data[2], + lastX, + lastY + ); + break; + case "q": + path.quadraticCurveTo( + lastX + data[1], + lastY + data[2], + lastX + data[3], + lastY + data[4] + ); + lastX += data[3]; + lastY += data[4]; + break; + case "T": + lastX = data[1]; + lastY = data[2]; + path.quadraticCurveToShort( + lastX, + lastY + ); + break; + case "t": + lastX += data[1]; + lastY += data[2]; + path.quadraticCurveToShort( + lastX, + lastY + ); + break; + case "A": + lastX = data[6]; + lastY = data[7]; + path.arcToSvg( + data[1], + data[2], + data[3], + data[4], + data[5], + lastX, + lastY + ); + break; + case "a": + lastX += data[6]; + lastY += data[7]; + path.arcToSvg( + data[1], + data[2], + data[3], + data[4], + data[5], + lastX, + lastY + ); + break; + case "Z": + case "z": + path.closePath(); + if (subpaths.length > 0) { + currentSubPath = subpaths.pop(); + if (currentSubPath) { + lastX = currentSubPath.startX; + lastY = currentSubPath.startY; + } else { + lastX = 0; + lastY = 0; + } + } + currentSubPath = null; + break; + default: + warn(`Unknown SVG path command: ${type}`); + } + if (type !== "Z" && type !== "z") { + if (currentSubPath === null) { + currentSubPath = { startX: lastX, startY: lastY }; + subpaths.push(currentSubPath); + } + } + } + return path; + } + + "use strict"; + class Circle { + /** + * @param x - The X coordinate of the center of this circle + * @param y - The Y coordinate of the center of this circle + * @param radius - The radius of the circle + */ + constructor(x = 0, y = 0, radius = 0) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'circle' + */ + this.type = "circle"; + this.x = x; + this.y = y; + this.radius = radius; + } + /** + * Creates a clone of this Circle instance + * @returns A copy of the Circle + */ + clone() { + return new Circle(this.x, this.y, this.radius); + } + /** + * Checks whether the x and y coordinates given are contained within this circle + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @returns Whether the x/y coordinates are within this Circle + */ + contains(x, y) { + if (this.radius <= 0) + return false; + const r2 = this.radius * this.radius; + let dx = this.x - x; + let dy = this.y - y; + dx *= dx; + dy *= dy; + return dx + dy <= r2; + } + /** + * Checks whether the x and y coordinates given are contained within this circle including the stroke. + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @param width - The width of the line to check + * @returns Whether the x/y coordinates are within this Circle + */ + strokeContains(x, y, width) { + if (this.radius === 0) + return false; + const dx = this.x - x; + const dy = this.y - y; + const r = this.radius; + const w2 = width / 2; + const distance = Math.sqrt(dx * dx + dy * dy); + return distance < r + w2 && distance > r - w2; + } + /** + * Returns the framing rectangle of the circle as a Rectangle object + * @param out + * @returns The framing rectangle + */ + getBounds(out) { + out = out || new Rectangle(); + out.x = this.x - this.radius; + out.y = this.y - this.radius; + out.width = this.radius * 2; + out.height = this.radius * 2; + return out; + } + /** + * Copies another circle to this one. + * @param circle - The circle to copy from. + * @returns Returns itself. + */ + copyFrom(circle) { + this.x = circle.x; + this.y = circle.y; + this.radius = circle.radius; + return this; + } + /** + * Copies this circle to another one. + * @param circle - The circle to copy to. + * @returns Returns given parameter. + */ + copyTo(circle) { + circle.copyFrom(this); + return circle; + } + toString() { + return `[pixi.js/math:Circle x=${this.x} y=${this.y} radius=${this.radius}]`; + } + } + + "use strict"; + class Ellipse { + /** + * @param x - The X coordinate of the center of this ellipse + * @param y - The Y coordinate of the center of this ellipse + * @param halfWidth - The half width of this ellipse + * @param halfHeight - The half height of this ellipse + */ + constructor(x = 0, y = 0, halfWidth = 0, halfHeight = 0) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'ellipse' + */ + this.type = "ellipse"; + this.x = x; + this.y = y; + this.halfWidth = halfWidth; + this.halfHeight = halfHeight; + } + /** + * Creates a clone of this Ellipse instance + * @returns {Ellipse} A copy of the ellipse + */ + clone() { + return new Ellipse(this.x, this.y, this.halfWidth, this.halfHeight); + } + /** + * Checks whether the x and y coordinates given are contained within this ellipse + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @returns Whether the x/y coords are within this ellipse + */ + contains(x, y) { + if (this.halfWidth <= 0 || this.halfHeight <= 0) { + return false; + } + let normx = (x - this.x) / this.halfWidth; + let normy = (y - this.y) / this.halfHeight; + normx *= normx; + normy *= normy; + return normx + normy <= 1; + } + /** + * Checks whether the x and y coordinates given are contained within this ellipse including stroke + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @param width + * @returns Whether the x/y coords are within this ellipse + */ + strokeContains(x, y, width) { + const { halfWidth, halfHeight } = this; + if (halfWidth <= 0 || halfHeight <= 0) { + return false; + } + const halfStrokeWidth = width / 2; + const innerA = halfWidth - halfStrokeWidth; + const innerB = halfHeight - halfStrokeWidth; + const outerA = halfWidth + halfStrokeWidth; + const outerB = halfHeight + halfStrokeWidth; + const normalizedX = x - this.x; + const normalizedY = y - this.y; + const innerEllipse = normalizedX * normalizedX / (innerA * innerA) + normalizedY * normalizedY / (innerB * innerB); + const outerEllipse = normalizedX * normalizedX / (outerA * outerA) + normalizedY * normalizedY / (outerB * outerB); + return innerEllipse > 1 && outerEllipse <= 1; + } + /** + * Returns the framing rectangle of the ellipse as a Rectangle object + * @returns The framing rectangle + */ + getBounds() { + return new Rectangle(this.x - this.halfWidth, this.y - this.halfHeight, this.halfWidth * 2, this.halfHeight * 2); + } + /** + * Copies another ellipse to this one. + * @param ellipse - The ellipse to copy from. + * @returns Returns itself. + */ + copyFrom(ellipse) { + this.x = ellipse.x; + this.y = ellipse.y; + this.halfWidth = ellipse.halfWidth; + this.halfHeight = ellipse.halfHeight; + return this; + } + /** + * Copies this ellipse to another one. + * @param ellipse - The ellipse to copy to. + * @returns Returns given parameter. + */ + copyTo(ellipse) { + ellipse.copyFrom(this); + return ellipse; + } + toString() { + return `[pixi.js/math:Ellipse x=${this.x} y=${this.y} halfWidth=${this.halfWidth} halfHeight=${this.halfHeight}]`; + } + } + + "use strict"; + function squaredDistanceToLineSegment(x, y, x1, y1, x2, y2) { + const a = x - x1; + const b = y - y1; + const c = x2 - x1; + const d = y2 - y1; + const dot = a * c + b * d; + const lenSq = c * c + d * d; + let param = -1; + if (lenSq !== 0) { + param = dot / lenSq; + } + let xx; + let yy; + if (param < 0) { + xx = x1; + yy = y1; + } else if (param > 1) { + xx = x2; + yy = y2; + } else { + xx = x1 + param * c; + yy = y1 + param * d; + } + const dx = x - xx; + const dy = y - yy; + return dx * dx + dy * dy; + } + + "use strict"; + class Polygon { + /** + * @param points - This can be an array of Points + * that form the polygon, a flat array of numbers that will be interpreted as [x,y, x,y, ...], or + * the arguments passed can be all the points of the polygon e.g. + * `new Polygon(new Point(), new Point(), ...)`, or the arguments passed can be flat + * x,y values e.g. `new Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are Numbers. + */ + constructor(...points) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'polygon' + */ + this.type = "polygon"; + let flat = Array.isArray(points[0]) ? points[0] : points; + if (typeof flat[0] !== "number") { + const p = []; + for (let i = 0, il = flat.length; i < il; i++) { + p.push(flat[i].x, flat[i].y); + } + flat = p; + } + this.points = flat; + this.closePath = true; + } + /** + * Creates a clone of this polygon. + * @returns - A copy of the polygon. + */ + clone() { + const points = this.points.slice(); + const polygon = new Polygon(points); + polygon.closePath = this.closePath; + return polygon; + } + /** + * Checks whether the x and y coordinates passed to this function are contained within this polygon. + * @param x - The X coordinate of the point to test. + * @param y - The Y coordinate of the point to test. + * @returns - Whether the x/y coordinates are within this polygon. + */ + contains(x, y) { + let inside = false; + const length = this.points.length / 2; + for (let i = 0, j = length - 1; i < length; j = i++) { + const xi = this.points[i * 2]; + const yi = this.points[i * 2 + 1]; + const xj = this.points[j * 2]; + const yj = this.points[j * 2 + 1]; + const intersect = yi > y !== yj > y && x < (xj - xi) * ((y - yi) / (yj - yi)) + xi; + if (intersect) { + inside = !inside; + } + } + return inside; + } + /** + * Checks whether the x and y coordinates given are contained within this polygon including the stroke. + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @param strokeWidth - The width of the line to check + * @returns Whether the x/y coordinates are within this polygon + */ + strokeContains(x, y, strokeWidth) { + const halfStrokeWidth = strokeWidth / 2; + const halfStrokeWidthSqrd = halfStrokeWidth * halfStrokeWidth; + const { points } = this; + const iterationLength = points.length - (this.closePath ? 0 : 2); + for (let i = 0; i < iterationLength; i += 2) { + const x1 = points[i]; + const y1 = points[i + 1]; + const x2 = points[(i + 2) % points.length]; + const y2 = points[(i + 3) % points.length]; + const distanceSqrd = squaredDistanceToLineSegment(x, y, x1, y1, x2, y2); + if (distanceSqrd <= halfStrokeWidthSqrd) { + return true; + } + } + return false; + } + /** + * Returns the framing rectangle of the polygon as a Rectangle object + * @param out - optional rectangle to store the result + * @returns The framing rectangle + */ + getBounds(out) { + out = out || new Rectangle(); + const points = this.points; + let minX = Infinity; + let maxX = -Infinity; + let minY = Infinity; + let maxY = -Infinity; + for (let i = 0, n = points.length; i < n; i += 2) { + const x = points[i]; + const y = points[i + 1]; + minX = x < minX ? x : minX; + maxX = x > maxX ? x : maxX; + minY = y < minY ? y : minY; + maxY = y > maxY ? y : maxY; + } + out.x = minX; + out.width = maxX - minX; + out.y = minY; + out.height = maxY - minY; + return out; + } + /** + * Copies another polygon to this one. + * @param polygon - The polygon to copy from. + * @returns Returns itself. + */ + copyFrom(polygon) { + this.points = polygon.points.slice(); + this.closePath = polygon.closePath; + return this; + } + /** + * Copies this polygon to another one. + * @param polygon - The polygon to copy to. + * @returns Returns given parameter. + */ + copyTo(polygon) { + polygon.copyFrom(this); + return polygon; + } + toString() { + return `[pixi.js/math:PolygoncloseStroke=${this.closePath}points=${this.points.reduce((pointsDesc, currentPoint) => `${pointsDesc}, ${currentPoint}`, "")}]`; + } + /** + * Get the last X coordinate of the polygon + * @readonly + */ + get lastX() { + return this.points[this.points.length - 2]; + } + /** + * Get the last Y coordinate of the polygon + * @readonly + */ + get lastY() { + return this.points[this.points.length - 1]; + } + /** + * Get the first X coordinate of the polygon + * @readonly + */ + get x() { + return this.points[this.points.length - 2]; + } + /** + * Get the first Y coordinate of the polygon + * @readonly + */ + get y() { + return this.points[this.points.length - 1]; + } + } + + "use strict"; + const isCornerWithinStroke = (pX, pY, cornerX, cornerY, radius, halfStrokeWidth) => { + const dx = pX - cornerX; + const dy = pY - cornerY; + const distance = Math.sqrt(dx * dx + dy * dy); + return distance >= radius - halfStrokeWidth && distance <= radius + halfStrokeWidth; + }; + class RoundedRectangle { + /** + * @param x - The X coordinate of the upper-left corner of the rounded rectangle + * @param y - The Y coordinate of the upper-left corner of the rounded rectangle + * @param width - The overall width of this rounded rectangle + * @param height - The overall height of this rounded rectangle + * @param radius - Controls the radius of the rounded corners + */ + constructor(x = 0, y = 0, width = 0, height = 0, radius = 20) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'roundedRectangle' + */ + this.type = "roundedRectangle"; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.radius = radius; + } + /** + * Returns the framing rectangle of the rounded rectangle as a Rectangle object + * @param out - optional rectangle to store the result + * @returns The framing rectangle + */ + getBounds(out) { + out = out || new Rectangle(); + out.x = this.x; + out.y = this.y; + out.width = this.width; + out.height = this.height; + return out; + } + /** + * Creates a clone of this Rounded Rectangle. + * @returns - A copy of the rounded rectangle. + */ + clone() { + return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius); + } + /** + * Copies another rectangle to this one. + * @param rectangle - The rectangle to copy from. + * @returns Returns itself. + */ + copyFrom(rectangle) { + this.x = rectangle.x; + this.y = rectangle.y; + this.width = rectangle.width; + this.height = rectangle.height; + return this; + } + /** + * Copies this rectangle to another one. + * @param rectangle - The rectangle to copy to. + * @returns Returns given parameter. + */ + copyTo(rectangle) { + rectangle.copyFrom(this); + return rectangle; + } + /** + * Checks whether the x and y coordinates given are contained within this Rounded Rectangle + * @param x - The X coordinate of the point to test. + * @param y - The Y coordinate of the point to test. + * @returns - Whether the x/y coordinates are within this Rounded Rectangle. + */ + contains(x, y) { + if (this.width <= 0 || this.height <= 0) { + return false; + } + if (x >= this.x && x <= this.x + this.width) { + if (y >= this.y && y <= this.y + this.height) { + const radius = Math.max(0, Math.min(this.radius, Math.min(this.width, this.height) / 2)); + if (y >= this.y + radius && y <= this.y + this.height - radius || x >= this.x + radius && x <= this.x + this.width - radius) { + return true; + } + let dx = x - (this.x + radius); + let dy = y - (this.y + radius); + const radius2 = radius * radius; + if (dx * dx + dy * dy <= radius2) { + return true; + } + dx = x - (this.x + this.width - radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + dy = y - (this.y + this.height - radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + dx = x - (this.x + radius); + if (dx * dx + dy * dy <= radius2) { + return true; + } + } + } + return false; + } + /** + * Checks whether the x and y coordinates given are contained within this rectangle including the stroke. + * @param pX - The X coordinate of the point to test + * @param pY - The Y coordinate of the point to test + * @param strokeWidth - The width of the line to check + * @returns Whether the x/y coordinates are within this rectangle + */ + strokeContains(pX, pY, strokeWidth) { + const { x, y, width, height, radius } = this; + const halfStrokeWidth = strokeWidth / 2; + const innerX = x + radius; + const innerY = y + radius; + const innerWidth = width - radius * 2; + const innerHeight = height - radius * 2; + const rightBound = x + width; + const bottomBound = y + height; + if ((pX >= x - halfStrokeWidth && pX <= x + halfStrokeWidth || pX >= rightBound - halfStrokeWidth && pX <= rightBound + halfStrokeWidth) && pY >= innerY && pY <= innerY + innerHeight) { + return true; + } + if ((pY >= y - halfStrokeWidth && pY <= y + halfStrokeWidth || pY >= bottomBound - halfStrokeWidth && pY <= bottomBound + halfStrokeWidth) && pX >= innerX && pX <= innerX + innerWidth) { + return true; + } + return ( + // Top-left + pX < innerX && pY < innerY && isCornerWithinStroke(pX, pY, innerX, innerY, radius, halfStrokeWidth) || pX > rightBound - radius && pY < innerY && isCornerWithinStroke(pX, pY, rightBound - radius, innerY, radius, halfStrokeWidth) || pX > rightBound - radius && pY > bottomBound - radius && isCornerWithinStroke(pX, pY, rightBound - radius, bottomBound - radius, radius, halfStrokeWidth) || pX < innerX && pY > bottomBound - radius && isCornerWithinStroke(pX, pY, innerX, bottomBound - radius, radius, halfStrokeWidth) + ); + } + toString() { + return `[pixi.js/math:RoundedRectangle x=${this.x} y=${this.y}width=${this.width} height=${this.height} radius=${this.radius}]`; + } + } + + "use strict"; + const RECURSION_LIMIT$1 = 8; + const FLT_EPSILON$1 = 11920929e-14; + const PATH_DISTANCE_EPSILON$1 = 1; + const curveAngleToleranceEpsilon$1 = 0.01; + const mAngleTolerance$1 = 0; + const mCuspLimit = 0; + function buildAdaptiveBezier(points, sX, sY, cp1x, cp1y, cp2x, cp2y, eX, eY, smoothness) { + const scale = 1; + const smoothing = Math.min( + 0.99, + // a value of 1.0 actually inverts smoothing, so we cap it at 0.99 + Math.max(0, smoothness != null ? smoothness : GraphicsContextSystem.defaultOptions.bezierSmoothness) + ); + let distanceTolerance = (PATH_DISTANCE_EPSILON$1 - smoothing) / scale; + distanceTolerance *= distanceTolerance; + begin$1(sX, sY, cp1x, cp1y, cp2x, cp2y, eX, eY, points, distanceTolerance); + return points; + } + function begin$1(sX, sY, cp1x, cp1y, cp2x, cp2y, eX, eY, points, distanceTolerance) { + recursive$1(sX, sY, cp1x, cp1y, cp2x, cp2y, eX, eY, points, distanceTolerance, 0); + points.push(eX, eY); + } + function recursive$1(x1, y1, x2, y2, x3, y3, x4, y4, points, distanceTolerance, level) { + if (level > RECURSION_LIMIT$1) { + return; + } + const pi = Math.PI; + const x12 = (x1 + x2) / 2; + const y12 = (y1 + y2) / 2; + const x23 = (x2 + x3) / 2; + const y23 = (y2 + y3) / 2; + const x34 = (x3 + x4) / 2; + const y34 = (y3 + y4) / 2; + const x123 = (x12 + x23) / 2; + const y123 = (y12 + y23) / 2; + const x234 = (x23 + x34) / 2; + const y234 = (y23 + y34) / 2; + const x1234 = (x123 + x234) / 2; + const y1234 = (y123 + y234) / 2; + if (level > 0) { + let dx = x4 - x1; + let dy = y4 - y1; + const d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx); + const d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx); + let da1; + let da2; + if (d2 > FLT_EPSILON$1 && d3 > FLT_EPSILON$1) { + if ((d2 + d3) * (d2 + d3) <= distanceTolerance * (dx * dx + dy * dy)) { + if (mAngleTolerance$1 < curveAngleToleranceEpsilon$1) { + points.push(x1234, y1234); + return; + } + const a23 = Math.atan2(y3 - y2, x3 - x2); + da1 = Math.abs(a23 - Math.atan2(y2 - y1, x2 - x1)); + da2 = Math.abs(Math.atan2(y4 - y3, x4 - x3) - a23); + if (da1 >= pi) + da1 = 2 * pi - da1; + if (da2 >= pi) + da2 = 2 * pi - da2; + if (da1 + da2 < mAngleTolerance$1) { + points.push(x1234, y1234); + return; + } + if (mCuspLimit !== 0) { + if (da1 > mCuspLimit) { + points.push(x2, y2); + return; + } + if (da2 > mCuspLimit) { + points.push(x3, y3); + return; + } + } + } + } else if (d2 > FLT_EPSILON$1) { + if (d2 * d2 <= distanceTolerance * (dx * dx + dy * dy)) { + if (mAngleTolerance$1 < curveAngleToleranceEpsilon$1) { + points.push(x1234, y1234); + return; + } + da1 = Math.abs(Math.atan2(y3 - y2, x3 - x2) - Math.atan2(y2 - y1, x2 - x1)); + if (da1 >= pi) + da1 = 2 * pi - da1; + if (da1 < mAngleTolerance$1) { + points.push(x2, y2); + points.push(x3, y3); + return; + } + if (mCuspLimit !== 0) { + if (da1 > mCuspLimit) { + points.push(x2, y2); + return; + } + } + } + } else if (d3 > FLT_EPSILON$1) { + if (d3 * d3 <= distanceTolerance * (dx * dx + dy * dy)) { + if (mAngleTolerance$1 < curveAngleToleranceEpsilon$1) { + points.push(x1234, y1234); + return; + } + da1 = Math.abs(Math.atan2(y4 - y3, x4 - x3) - Math.atan2(y3 - y2, x3 - x2)); + if (da1 >= pi) + da1 = 2 * pi - da1; + if (da1 < mAngleTolerance$1) { + points.push(x2, y2); + points.push(x3, y3); + return; + } + if (mCuspLimit !== 0) { + if (da1 > mCuspLimit) { + points.push(x3, y3); + return; + } + } + } + } else { + dx = x1234 - (x1 + x4) / 2; + dy = y1234 - (y1 + y4) / 2; + if (dx * dx + dy * dy <= distanceTolerance) { + points.push(x1234, y1234); + return; + } + } + } + recursive$1(x1, y1, x12, y12, x123, y123, x1234, y1234, points, distanceTolerance, level + 1); + recursive$1(x1234, y1234, x234, y234, x34, y34, x4, y4, points, distanceTolerance, level + 1); + } + + "use strict"; + const RECURSION_LIMIT = 8; + const FLT_EPSILON = 11920929e-14; + const PATH_DISTANCE_EPSILON = 1; + const curveAngleToleranceEpsilon = 0.01; + const mAngleTolerance = 0; + function buildAdaptiveQuadratic(points, sX, sY, cp1x, cp1y, eX, eY, smoothness) { + const scale = 1; + const smoothing = Math.min( + 0.99, + // a value of 1.0 actually inverts smoothing, so we cap it at 0.99 + Math.max(0, smoothness != null ? smoothness : GraphicsContextSystem.defaultOptions.bezierSmoothness) + ); + let distanceTolerance = (PATH_DISTANCE_EPSILON - smoothing) / scale; + distanceTolerance *= distanceTolerance; + begin(sX, sY, cp1x, cp1y, eX, eY, points, distanceTolerance); + return points; + } + function begin(sX, sY, cp1x, cp1y, eX, eY, points, distanceTolerance) { + recursive(points, sX, sY, cp1x, cp1y, eX, eY, distanceTolerance, 0); + points.push(eX, eY); + } + function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) { + if (level > RECURSION_LIMIT) { + return; + } + const pi = Math.PI; + const x12 = (x1 + x2) / 2; + const y12 = (y1 + y2) / 2; + const x23 = (x2 + x3) / 2; + const y23 = (y2 + y3) / 2; + const x123 = (x12 + x23) / 2; + const y123 = (y12 + y23) / 2; + let dx = x3 - x1; + let dy = y3 - y1; + const d = Math.abs((x2 - x3) * dy - (y2 - y3) * dx); + if (d > FLT_EPSILON) { + if (d * d <= distanceTolerance * (dx * dx + dy * dy)) { + if (mAngleTolerance < curveAngleToleranceEpsilon) { + points.push(x123, y123); + return; + } + let da = Math.abs(Math.atan2(y3 - y2, x3 - x2) - Math.atan2(y2 - y1, x2 - x1)); + if (da >= pi) + da = 2 * pi - da; + if (da < mAngleTolerance) { + points.push(x123, y123); + return; + } + } + } else { + dx = x123 - (x1 + x3) / 2; + dy = y123 - (y1 + y3) / 2; + if (dx * dx + dy * dy <= distanceTolerance) { + points.push(x123, y123); + return; + } + } + recursive(points, x1, y1, x12, y12, x123, y123, distanceTolerance, level + 1); + recursive(points, x123, y123, x23, y23, x3, y3, distanceTolerance, level + 1); + } + + "use strict"; + function buildArc(points, x, y, radius, start, end, clockwise, steps) { + let dist = Math.abs(start - end); + if (!clockwise && start > end) { + dist = 2 * Math.PI - dist; + } else if (clockwise && end > start) { + dist = 2 * Math.PI - dist; + } + steps = steps || Math.max(6, Math.floor(6 * Math.pow(radius, 1 / 3) * (dist / Math.PI))); + steps = Math.max(steps, 3); + let f = dist / steps; + let t = start; + f *= clockwise ? -1 : 1; + for (let i = 0; i < steps + 1; i++) { + const cs = Math.cos(t); + const sn = Math.sin(t); + const nx = x + cs * radius; + const ny = y + sn * radius; + points.push(nx, ny); + t += f; + } + } + + "use strict"; + function buildArcTo(points, x1, y1, x2, y2, radius) { + const fromX = points[points.length - 2]; + const fromY = points[points.length - 1]; + const a1 = fromY - y1; + const b1 = fromX - x1; + const a2 = y2 - y1; + const b2 = x2 - x1; + const mm = Math.abs(a1 * b2 - b1 * a2); + if (mm < 1e-8 || radius === 0) { + if (points[points.length - 2] !== x1 || points[points.length - 1] !== y1) { + points.push(x1, y1); + } + return; + } + const dd = a1 * a1 + b1 * b1; + const cc = a2 * a2 + b2 * b2; + const tt = a1 * a2 + b1 * b2; + const k1 = radius * Math.sqrt(dd) / mm; + const k2 = radius * Math.sqrt(cc) / mm; + const j1 = k1 * tt / dd; + const j2 = k2 * tt / cc; + const cx = k1 * b2 + k2 * b1; + const cy = k1 * a2 + k2 * a1; + const px = b1 * (k2 + j1); + const py = a1 * (k2 + j1); + const qx = b2 * (k1 + j2); + const qy = a2 * (k1 + j2); + const startAngle = Math.atan2(py - cy, px - cx); + const endAngle = Math.atan2(qy - cy, qx - cx); + buildArc( + points, + cx + x1, + cy + y1, + radius, + startAngle, + endAngle, + b1 * a2 > b2 * a1 + ); + } + + "use strict"; + const TAU = Math.PI * 2; + const out = { + centerX: 0, + centerY: 0, + ang1: 0, + ang2: 0 + }; + const mapToEllipse = ({ x, y }, rx, ry, cosPhi, sinPhi, centerX, centerY, out2) => { + x *= rx; + y *= ry; + const xp = cosPhi * x - sinPhi * y; + const yp = sinPhi * x + cosPhi * y; + out2.x = xp + centerX; + out2.y = yp + centerY; + return out2; + }; + function approxUnitArc(ang1, ang2) { + const a1 = ang2 === -1.5707963267948966 ? -0.551915024494 : 4 / 3 * Math.tan(ang2 / 4); + const a = ang2 === 1.5707963267948966 ? 0.551915024494 : a1; + const x1 = Math.cos(ang1); + const y1 = Math.sin(ang1); + const x2 = Math.cos(ang1 + ang2); + const y2 = Math.sin(ang1 + ang2); + return [ + { + x: x1 - y1 * a, + y: y1 + x1 * a + }, + { + x: x2 + y2 * a, + y: y2 - x2 * a + }, + { + x: x2, + y: y2 + } + ]; + } + const vectorAngle = (ux, uy, vx, vy) => { + const sign = ux * vy - uy * vx < 0 ? -1 : 1; + let dot = ux * vx + uy * vy; + if (dot > 1) { + dot = 1; + } + if (dot < -1) { + dot = -1; + } + return sign * Math.acos(dot); + }; + const getArcCenter = (px, py, cx, cy, rx, ry, largeArcFlag, sweepFlag, sinPhi, cosPhi, pxp, pyp, out2) => { + const rxSq = Math.pow(rx, 2); + const rySq = Math.pow(ry, 2); + const pxpSq = Math.pow(pxp, 2); + const pypSq = Math.pow(pyp, 2); + let radicant = rxSq * rySq - rxSq * pypSq - rySq * pxpSq; + if (radicant < 0) { + radicant = 0; + } + radicant /= rxSq * pypSq + rySq * pxpSq; + radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1); + const centerXp = radicant * rx / ry * pyp; + const centerYp = radicant * -ry / rx * pxp; + const centerX = cosPhi * centerXp - sinPhi * centerYp + (px + cx) / 2; + const centerY = sinPhi * centerXp + cosPhi * centerYp + (py + cy) / 2; + const vx1 = (pxp - centerXp) / rx; + const vy1 = (pyp - centerYp) / ry; + const vx2 = (-pxp - centerXp) / rx; + const vy2 = (-pyp - centerYp) / ry; + const ang1 = vectorAngle(1, 0, vx1, vy1); + let ang2 = vectorAngle(vx1, vy1, vx2, vy2); + if (sweepFlag === 0 && ang2 > 0) { + ang2 -= TAU; + } + if (sweepFlag === 1 && ang2 < 0) { + ang2 += TAU; + } + out2.centerX = centerX; + out2.centerY = centerY; + out2.ang1 = ang1; + out2.ang2 = ang2; + }; + function buildArcToSvg(points, px, py, cx, cy, rx, ry, xAxisRotation = 0, largeArcFlag = 0, sweepFlag = 0) { + if (rx === 0 || ry === 0) { + return; + } + const sinPhi = Math.sin(xAxisRotation * TAU / 360); + const cosPhi = Math.cos(xAxisRotation * TAU / 360); + const pxp = cosPhi * (px - cx) / 2 + sinPhi * (py - cy) / 2; + const pyp = -sinPhi * (px - cx) / 2 + cosPhi * (py - cy) / 2; + if (pxp === 0 && pyp === 0) { + return; + } + rx = Math.abs(rx); + ry = Math.abs(ry); + const lambda = Math.pow(pxp, 2) / Math.pow(rx, 2) + Math.pow(pyp, 2) / Math.pow(ry, 2); + if (lambda > 1) { + rx *= Math.sqrt(lambda); + ry *= Math.sqrt(lambda); + } + getArcCenter( + px, + py, + cx, + cy, + rx, + ry, + largeArcFlag, + sweepFlag, + sinPhi, + cosPhi, + pxp, + pyp, + out + ); + let { ang1, ang2 } = out; + const { centerX, centerY } = out; + let ratio = Math.abs(ang2) / (TAU / 4); + if (Math.abs(1 - ratio) < 1e-7) { + ratio = 1; + } + const segments = Math.max(Math.ceil(ratio), 1); + ang2 /= segments; + let lastX = points[points.length - 2]; + let lastY = points[points.length - 1]; + const outCurvePoint = { x: 0, y: 0 }; + for (let i = 0; i < segments; i++) { + const curve = approxUnitArc(ang1, ang2); + const { x: x1, y: y1 } = mapToEllipse(curve[0], rx, ry, cosPhi, sinPhi, centerX, centerY, outCurvePoint); + const { x: x2, y: y2 } = mapToEllipse(curve[1], rx, ry, cosPhi, sinPhi, centerX, centerY, outCurvePoint); + const { x, y } = mapToEllipse(curve[2], rx, ry, cosPhi, sinPhi, centerX, centerY, outCurvePoint); + buildAdaptiveBezier( + points, + lastX, + lastY, + x1, + y1, + x2, + y2, + x, + y + ); + lastX = x; + lastY = y; + ang1 += ang2; + } + } + + "use strict"; + function roundedShapeArc(g, points, radius) { + var _a; + const vecFrom = (p, pp) => { + const x = pp.x - p.x; + const y = pp.y - p.y; + const len = Math.sqrt(x * x + y * y); + const nx = x / len; + const ny = y / len; + return { len, nx, ny }; + }; + const sharpCorner = (i, p) => { + if (i === 0) { + g.moveTo(p.x, p.y); + } else { + g.lineTo(p.x, p.y); + } + }; + let p1 = points[points.length - 1]; + for (let i = 0; i < points.length; i++) { + const p2 = points[i % points.length]; + const pRadius = (_a = p2.radius) != null ? _a : radius; + if (pRadius <= 0) { + sharpCorner(i, p2); + p1 = p2; + continue; + } + const p3 = points[(i + 1) % points.length]; + const v1 = vecFrom(p2, p1); + const v2 = vecFrom(p2, p3); + if (v1.len < 1e-4 || v2.len < 1e-4) { + sharpCorner(i, p2); + p1 = p2; + continue; + } + let angle = Math.asin(v1.nx * v2.ny - v1.ny * v2.nx); + let radDirection = 1; + let drawDirection = false; + if (v1.nx * v2.nx - v1.ny * -v2.ny < 0) { + if (angle < 0) { + angle = Math.PI + angle; + } else { + angle = Math.PI - angle; + radDirection = -1; + drawDirection = true; + } + } else if (angle > 0) { + radDirection = -1; + drawDirection = true; + } + const halfAngle = angle / 2; + let cRadius; + let lenOut = Math.abs( + Math.cos(halfAngle) * pRadius / Math.sin(halfAngle) + ); + if (lenOut > Math.min(v1.len / 2, v2.len / 2)) { + lenOut = Math.min(v1.len / 2, v2.len / 2); + cRadius = Math.abs(lenOut * Math.sin(halfAngle) / Math.cos(halfAngle)); + } else { + cRadius = pRadius; + } + const cX = p2.x + v2.nx * lenOut + -v2.ny * cRadius * radDirection; + const cY = p2.y + v2.ny * lenOut + v2.nx * cRadius * radDirection; + const startAngle = Math.atan2(v1.ny, v1.nx) + Math.PI / 2 * radDirection; + const endAngle = Math.atan2(v2.ny, v2.nx) - Math.PI / 2 * radDirection; + if (i === 0) { + g.moveTo( + cX + Math.cos(startAngle) * cRadius, + cY + Math.sin(startAngle) * cRadius + ); + } + g.arc(cX, cY, cRadius, startAngle, endAngle, drawDirection); + p1 = p2; + } + } + function roundedShapeQuadraticCurve(g, points, radius, smoothness) { + var _a; + const distance = (p1, p2) => Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2); + const pointLerp = (p1, p2, t) => ({ + x: p1.x + (p2.x - p1.x) * t, + y: p1.y + (p2.y - p1.y) * t + }); + const numPoints = points.length; + for (let i = 0; i < numPoints; i++) { + const thisPoint = points[(i + 1) % numPoints]; + const pRadius = (_a = thisPoint.radius) != null ? _a : radius; + if (pRadius <= 0) { + if (i === 0) { + g.moveTo(thisPoint.x, thisPoint.y); + } else { + g.lineTo(thisPoint.x, thisPoint.y); + } + continue; + } + const lastPoint = points[i]; + const nextPoint = points[(i + 2) % numPoints]; + const lastEdgeLength = distance(lastPoint, thisPoint); + let start; + if (lastEdgeLength < 1e-4) { + start = thisPoint; + } else { + const lastOffsetDistance = Math.min(lastEdgeLength / 2, pRadius); + start = pointLerp( + thisPoint, + lastPoint, + lastOffsetDistance / lastEdgeLength + ); + } + const nextEdgeLength = distance(nextPoint, thisPoint); + let end; + if (nextEdgeLength < 1e-4) { + end = thisPoint; + } else { + const nextOffsetDistance = Math.min(nextEdgeLength / 2, pRadius); + end = pointLerp( + thisPoint, + nextPoint, + nextOffsetDistance / nextEdgeLength + ); + } + if (i === 0) { + g.moveTo(start.x, start.y); + } else { + g.lineTo(start.x, start.y); + } + g.quadraticCurveTo(thisPoint.x, thisPoint.y, end.x, end.y, smoothness); + } + } + + "use strict"; + const tempRectangle = new Rectangle(); + class ShapePath { + constructor(graphicsPath2D) { + /** The list of shape primitives that make up the path. */ + this.shapePrimitives = []; + this._currentPoly = null; + this._bounds = new Bounds(); + this._graphicsPath2D = graphicsPath2D; + } + /** + * Sets the starting point for a new sub-path. Any subsequent drawing commands are considered part of this path. + * @param x - The x-coordinate for the starting point. + * @param y - The y-coordinate for the starting point. + * @returns The instance of the current object for chaining. + */ + moveTo(x, y) { + this.startPoly(x, y); + return this; + } + /** + * Connects the current point to a new point with a straight line. This method updates the current path. + * @param x - The x-coordinate of the new point to connect to. + * @param y - The y-coordinate of the new point to connect to. + * @returns The instance of the current object for chaining. + */ + lineTo(x, y) { + this._ensurePoly(); + const points = this._currentPoly.points; + const fromX = points[points.length - 2]; + const fromY = points[points.length - 1]; + if (fromX !== x || fromY !== y) { + points.push(x, y); + } + return this; + } + /** + * Adds an arc to the path. The arc is centered at (x, y) + * position with radius `radius` starting at `startAngle` and ending at `endAngle`. + * @param x - The x-coordinate of the arc's center. + * @param y - The y-coordinate of the arc's center. + * @param radius - The radius of the arc. + * @param startAngle - The starting angle of the arc, in radians. + * @param endAngle - The ending angle of the arc, in radians. + * @param counterclockwise - Specifies whether the arc should be drawn in the anticlockwise direction. False by default. + * @returns The instance of the current object for chaining. + */ + arc(x, y, radius, startAngle, endAngle, counterclockwise) { + this._ensurePoly(false); + const points = this._currentPoly.points; + buildArc(points, x, y, radius, startAngle, endAngle, counterclockwise); + return this; + } + /** + * Adds an arc to the path with the arc tangent to the line joining two specified points. + * The arc radius is specified by `radius`. + * @param x1 - The x-coordinate of the first point. + * @param y1 - The y-coordinate of the first point. + * @param x2 - The x-coordinate of the second point. + * @param y2 - The y-coordinate of the second point. + * @param radius - The radius of the arc. + * @returns The instance of the current object for chaining. + */ + arcTo(x1, y1, x2, y2, radius) { + this._ensurePoly(); + const points = this._currentPoly.points; + buildArcTo(points, x1, y1, x2, y2, radius); + return this; + } + /** + * Adds an SVG-style arc to the path, allowing for elliptical arcs based on the SVG spec. + * @param rx - The x-radius of the ellipse. + * @param ry - The y-radius of the ellipse. + * @param xAxisRotation - The rotation of the ellipse's x-axis relative + * to the x-axis of the coordinate system, in degrees. + * @param largeArcFlag - Determines if the arc should be greater than or less than 180 degrees. + * @param sweepFlag - Determines if the arc should be swept in a positive angle direction. + * @param x - The x-coordinate of the arc's end point. + * @param y - The y-coordinate of the arc's end point. + * @returns The instance of the current object for chaining. + */ + arcToSvg(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + const points = this._currentPoly.points; + buildArcToSvg( + points, + this._currentPoly.lastX, + this._currentPoly.lastY, + x, + y, + rx, + ry, + xAxisRotation, + largeArcFlag, + sweepFlag + ); + return this; + } + /** + * Adds a cubic Bezier curve to the path. + * It requires three points: the first two are control points and the third one is the end point. + * The starting point is the last point in the current path. + * @param cp1x - The x-coordinate of the first control point. + * @param cp1y - The y-coordinate of the first control point. + * @param cp2x - The x-coordinate of the second control point. + * @param cp2y - The y-coordinate of the second control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothness - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, smoothness) { + this._ensurePoly(); + const currentPoly = this._currentPoly; + buildAdaptiveBezier( + this._currentPoly.points, + currentPoly.lastX, + currentPoly.lastY, + cp1x, + cp1y, + cp2x, + cp2y, + x, + y, + smoothness + ); + return this; + } + /** + * Adds a quadratic curve to the path. It requires two points: the control point and the end point. + * The starting point is the last point in the current path. + * @param cp1x - The x-coordinate of the control point. + * @param cp1y - The y-coordinate of the control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothing - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + quadraticCurveTo(cp1x, cp1y, x, y, smoothing) { + this._ensurePoly(); + const currentPoly = this._currentPoly; + buildAdaptiveQuadratic( + this._currentPoly.points, + currentPoly.lastX, + currentPoly.lastY, + cp1x, + cp1y, + x, + y, + smoothing + ); + return this; + } + /** + * Closes the current path by drawing a straight line back to the start. + * If the shape is already closed or there are no points in the path, this method does nothing. + * @returns The instance of the current object for chaining. + */ + closePath() { + this.endPoly(true); + return this; + } + /** + * Adds another path to the current path. This method allows for the combination of multiple paths into one. + * @param path - The `GraphicsPath` object representing the path to add. + * @param transform - An optional `Matrix` object to apply a transformation to the path before adding it. + * @returns The instance of the current object for chaining. + */ + addPath(path, transform) { + this.endPoly(); + if (transform && !transform.isIdentity()) { + path = path.clone(true); + path.transform(transform); + } + for (let i = 0; i < path.instructions.length; i++) { + const instruction = path.instructions[i]; + this[instruction.action](...instruction.data); + } + return this; + } + /** + * Finalizes the drawing of the current path. Optionally, it can close the path. + * @param closePath - A boolean indicating whether to close the path after finishing. False by default. + */ + finish(closePath = false) { + this.endPoly(closePath); + } + /** + * Draws a rectangle shape. This method adds a new rectangle path to the current drawing. + * @param x - The x-coordinate of the top-left corner of the rectangle. + * @param y - The y-coordinate of the top-left corner of the rectangle. + * @param w - The width of the rectangle. + * @param h - The height of the rectangle. + * @param transform - An optional `Matrix` object to apply a transformation to the rectangle. + * @returns The instance of the current object for chaining. + */ + rect(x, y, w, h, transform) { + this.drawShape(new Rectangle(x, y, w, h), transform); + return this; + } + /** + * Draws a circle shape. This method adds a new circle path to the current drawing. + * @param x - The x-coordinate of the center of the circle. + * @param y - The y-coordinate of the center of the circle. + * @param radius - The radius of the circle. + * @param transform - An optional `Matrix` object to apply a transformation to the circle. + * @returns The instance of the current object for chaining. + */ + circle(x, y, radius, transform) { + this.drawShape(new Circle(x, y, radius), transform); + return this; + } + /** + * Draws a polygon shape. This method allows for the creation of complex polygons by specifying a sequence of points. + * @param points - An array of numbers, or or an array of PointData objects eg [{x,y}, {x,y}, {x,y}] + * representing the x and y coordinates of the polygon's vertices, in sequence. + * @param close - A boolean indicating whether to close the polygon path. True by default. + * @param transform - An optional `Matrix` object to apply a transformation to the polygon. + * @returns The instance of the current object for chaining. + */ + poly(points, close, transform) { + const polygon = new Polygon(points); + polygon.closePath = close; + this.drawShape(polygon, transform); + return this; + } + /** + * Draws a regular polygon with a specified number of sides. All sides and angles are equal. + * @param x - The x-coordinate of the center of the polygon. + * @param y - The y-coordinate of the center of the polygon. + * @param radius - The radius of the circumscribed circle of the polygon. + * @param sides - The number of sides of the polygon. Must be 3 or more. + * @param rotation - The rotation angle of the polygon, in radians. Zero by default. + * @param transform - An optional `Matrix` object to apply a transformation to the polygon. + * @returns The instance of the current object for chaining. + */ + regularPoly(x, y, radius, sides, rotation = 0, transform) { + sides = Math.max(sides | 0, 3); + const startAngle = -1 * Math.PI / 2 + rotation; + const delta = Math.PI * 2 / sides; + const polygon = []; + for (let i = 0; i < sides; i++) { + const angle = i * delta + startAngle; + polygon.push( + x + radius * Math.cos(angle), + y + radius * Math.sin(angle) + ); + } + this.poly(polygon, true, transform); + return this; + } + /** + * Draws a polygon with rounded corners. + * Similar to `regularPoly` but with the ability to round the corners of the polygon. + * @param x - The x-coordinate of the center of the polygon. + * @param y - The y-coordinate of the center of the polygon. + * @param radius - The radius of the circumscribed circle of the polygon. + * @param sides - The number of sides of the polygon. Must be 3 or more. + * @param corner - The radius of the rounding of the corners. + * @param rotation - The rotation angle of the polygon, in radians. Zero by default. + * @param smoothness - Optional parameter to adjust the smoothness of the rounding. + * @returns The instance of the current object for chaining. + */ + roundPoly(x, y, radius, sides, corner, rotation = 0, smoothness) { + sides = Math.max(sides | 0, 3); + if (corner <= 0) { + return this.regularPoly(x, y, radius, sides, rotation); + } + const sideLength = radius * Math.sin(Math.PI / sides) - 1e-3; + corner = Math.min(corner, sideLength); + const startAngle = -1 * Math.PI / 2 + rotation; + const delta = Math.PI * 2 / sides; + const internalAngle = (sides - 2) * Math.PI / sides / 2; + for (let i = 0; i < sides; i++) { + const angle = i * delta + startAngle; + const x0 = x + radius * Math.cos(angle); + const y0 = y + radius * Math.sin(angle); + const a1 = angle + Math.PI + internalAngle; + const a2 = angle - Math.PI - internalAngle; + const x1 = x0 + corner * Math.cos(a1); + const y1 = y0 + corner * Math.sin(a1); + const x3 = x0 + corner * Math.cos(a2); + const y3 = y0 + corner * Math.sin(a2); + if (i === 0) { + this.moveTo(x1, y1); + } else { + this.lineTo(x1, y1); + } + this.quadraticCurveTo(x0, y0, x3, y3, smoothness); + } + return this.closePath(); + } + /** + * Draws a shape with rounded corners. This function supports custom radius for each corner of the shape. + * Optionally, corners can be rounded using a quadratic curve instead of an arc, providing a different aesthetic. + * @param points - An array of `RoundedPoint` representing the corners of the shape to draw. + * A minimum of 3 points is required. + * @param radius - The default radius for the corners. + * This radius is applied to all corners unless overridden in `points`. + * @param useQuadratic - If set to true, rounded corners are drawn using a quadraticCurve + * method instead of an arc method. Defaults to false. + * @param smoothness - Specifies the smoothness of the curve when `useQuadratic` is true. + * Higher values make the curve smoother. + * @returns The instance of the current object for chaining. + */ + roundShape(points, radius, useQuadratic = false, smoothness) { + if (points.length < 3) { + return this; + } + if (useQuadratic) { + roundedShapeQuadraticCurve(this, points, radius, smoothness); + } else { + roundedShapeArc(this, points, radius); + } + return this.closePath(); + } + /** + * Draw Rectangle with fillet corners. This is much like rounded rectangle + * however it support negative numbers as well for the corner radius. + * @param x - Upper left corner of rect + * @param y - Upper right corner of rect + * @param width - Width of rect + * @param height - Height of rect + * @param fillet - accept negative or positive values + */ + filletRect(x, y, width, height, fillet) { + if (fillet === 0) { + return this.rect(x, y, width, height); + } + const maxFillet = Math.min(width, height) / 2; + const inset = Math.min(maxFillet, Math.max(-maxFillet, fillet)); + const right = x + width; + const bottom = y + height; + const dir = inset < 0 ? -inset : 0; + const size = Math.abs(inset); + return this.moveTo(x, y + size).arcTo(x + dir, y + dir, x + size, y, size).lineTo(right - size, y).arcTo(right - dir, y + dir, right, y + size, size).lineTo(right, bottom - size).arcTo(right - dir, bottom - dir, x + width - size, bottom, size).lineTo(x + size, bottom).arcTo(x + dir, bottom - dir, x, bottom - size, size).closePath(); + } + /** + * Draw Rectangle with chamfer corners. These are angled corners. + * @param x - Upper left corner of rect + * @param y - Upper right corner of rect + * @param width - Width of rect + * @param height - Height of rect + * @param chamfer - non-zero real number, size of corner cutout + * @param transform + */ + chamferRect(x, y, width, height, chamfer, transform) { + if (chamfer <= 0) { + return this.rect(x, y, width, height); + } + const inset = Math.min(chamfer, Math.min(width, height) / 2); + const right = x + width; + const bottom = y + height; + const points = [ + x + inset, + y, + right - inset, + y, + right, + y + inset, + right, + bottom - inset, + right - inset, + bottom, + x + inset, + bottom, + x, + bottom - inset, + x, + y + inset + ]; + for (let i = points.length - 1; i >= 2; i -= 2) { + if (points[i] === points[i - 2] && points[i - 1] === points[i - 3]) { + points.splice(i - 1, 2); + } + } + return this.poly(points, true, transform); + } + /** + * Draws an ellipse at the specified location and with the given x and y radii. + * An optional transformation can be applied, allowing for rotation, scaling, and translation. + * @param x - The x-coordinate of the center of the ellipse. + * @param y - The y-coordinate of the center of the ellipse. + * @param radiusX - The horizontal radius of the ellipse. + * @param radiusY - The vertical radius of the ellipse. + * @param transform - An optional `Matrix` object to apply a transformation to the ellipse. This can include rotations. + * @returns The instance of the current object for chaining. + */ + ellipse(x, y, radiusX, radiusY, transform) { + this.drawShape(new Ellipse(x, y, radiusX, radiusY), transform); + return this; + } + /** + * Draws a rectangle with rounded corners. + * The corner radius can be specified to determine how rounded the corners should be. + * An optional transformation can be applied, which allows for rotation, scaling, and translation of the rectangle. + * @param x - The x-coordinate of the top-left corner of the rectangle. + * @param y - The y-coordinate of the top-left corner of the rectangle. + * @param w - The width of the rectangle. + * @param h - The height of the rectangle. + * @param radius - The radius of the rectangle's corners. If not specified, corners will be sharp. + * @param transform - An optional `Matrix` object to apply a transformation to the rectangle. + * @returns The instance of the current object for chaining. + */ + roundRect(x, y, w, h, radius, transform) { + this.drawShape(new RoundedRectangle(x, y, w, h, radius), transform); + return this; + } + /** + * Draws a given shape on the canvas. + * This is a generic method that can draw any type of shape specified by the `ShapePrimitive` parameter. + * An optional transformation matrix can be applied to the shape, allowing for complex transformations. + * @param shape - The shape to draw, defined as a `ShapePrimitive` object. + * @param matrix - An optional `Matrix` for transforming the shape. This can include rotations, + * scaling, and translations. + * @returns The instance of the current object for chaining. + */ + drawShape(shape, matrix) { + this.endPoly(); + this.shapePrimitives.push({ shape, transform: matrix }); + return this; + } + /** + * Starts a new polygon path from the specified starting point. + * This method initializes a new polygon or ends the current one if it exists. + * @param x - The x-coordinate of the starting point of the new polygon. + * @param y - The y-coordinate of the starting point of the new polygon. + * @returns The instance of the current object for chaining. + */ + startPoly(x, y) { + let currentPoly = this._currentPoly; + if (currentPoly) { + this.endPoly(); + } + currentPoly = new Polygon(); + currentPoly.points.push(x, y); + this._currentPoly = currentPoly; + return this; + } + /** + * Ends the current polygon path. If `closePath` is set to true, + * the path is closed by connecting the last point to the first one. + * This method finalizes the current polygon and prepares it for drawing or adding to the shape primitives. + * @param closePath - A boolean indicating whether to close the polygon by connecting the last point + * back to the starting point. False by default. + * @returns The instance of the current object for chaining. + */ + endPoly(closePath = false) { + const shape = this._currentPoly; + if (shape && shape.points.length > 2) { + shape.closePath = closePath; + this.shapePrimitives.push({ shape }); + } + this._currentPoly = null; + return this; + } + _ensurePoly(start = true) { + if (this._currentPoly) + return; + this._currentPoly = new Polygon(); + if (start) { + const lastShape = this.shapePrimitives[this.shapePrimitives.length - 1]; + if (lastShape) { + let lx = lastShape.shape.x; + let ly = lastShape.shape.y; + if (!lastShape.transform.isIdentity()) { + const t = lastShape.transform; + const tempX = lx; + lx = t.a * lx + t.c * ly + t.tx; + ly = t.b * tempX + t.d * ly + t.ty; + } + this._currentPoly.points.push(lx, ly); + } else { + this._currentPoly.points.push(0, 0); + } + } + } + /** Builds the path. */ + buildPath() { + const path = this._graphicsPath2D; + this.shapePrimitives.length = 0; + this._currentPoly = null; + for (let i = 0; i < path.instructions.length; i++) { + const instruction = path.instructions[i]; + this[instruction.action](...instruction.data); + } + this.finish(); + } + /** Gets the bounds of the path. */ + get bounds() { + const bounds = this._bounds; + bounds.clear(); + const shapePrimitives = this.shapePrimitives; + for (let i = 0; i < shapePrimitives.length; i++) { + const shapePrimitive = shapePrimitives[i]; + const boundsRect = shapePrimitive.shape.getBounds(tempRectangle); + if (shapePrimitive.transform) { + bounds.addRect(boundsRect, shapePrimitive.transform); + } else { + bounds.addRect(boundsRect); + } + } + return bounds; + } + } + + "use strict"; + class GraphicsPath { + /** + * Creates a `GraphicsPath` instance optionally from an SVG path string or an array of `PathInstruction`. + * @param instructions - An SVG path string or an array of `PathInstruction` objects. + */ + constructor(instructions) { + this.instructions = []; + this.uid = uid("graphicsPath"); + this._dirty = true; + var _a; + if (typeof instructions === "string") { + SVGToGraphicsPath(instructions, this); + } else { + this.instructions = (_a = instructions == null ? void 0 : instructions.slice()) != null ? _a : []; + } + } + /** + * Provides access to the internal shape path, ensuring it is up-to-date with the current instructions. + * @returns The `ShapePath` instance associated with this `GraphicsPath`. + */ + get shapePath() { + if (!this._shapePath) { + this._shapePath = new ShapePath(this); + } + if (this._dirty) { + this._dirty = false; + this._shapePath.buildPath(); + } + return this._shapePath; + } + /** + * Adds another `GraphicsPath` to this path, optionally applying a transformation. + * @param path - The `GraphicsPath` to add. + * @param transform - An optional transformation to apply to the added path. + * @returns The instance of the current object for chaining. + */ + addPath(path, transform) { + path = path.clone(); + this.instructions.push({ action: "addPath", data: [path, transform] }); + this._dirty = true; + return this; + } + arc(...args) { + this.instructions.push({ action: "arc", data: args }); + this._dirty = true; + return this; + } + arcTo(...args) { + this.instructions.push({ action: "arcTo", data: args }); + this._dirty = true; + return this; + } + arcToSvg(...args) { + this.instructions.push({ action: "arcToSvg", data: args }); + this._dirty = true; + return this; + } + bezierCurveTo(...args) { + this.instructions.push({ action: "bezierCurveTo", data: args }); + this._dirty = true; + return this; + } + /** + * Adds a cubic Bezier curve to the path. + * It requires two points: the second control point and the end point. The first control point is assumed to be + * The starting point is the last point in the current path. + * @param cp2x - The x-coordinate of the second control point. + * @param cp2y - The y-coordinate of the second control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothness - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + bezierCurveToShort(cp2x, cp2y, x, y, smoothness) { + const last = this.instructions[this.instructions.length - 1]; + const lastPoint = this.getLastPoint(Point.shared); + let cp1x = 0; + let cp1y = 0; + if (!last || last.action !== "bezierCurveTo") { + cp1x = lastPoint.x; + cp1y = lastPoint.y; + } else { + cp1x = last.data[2]; + cp1y = last.data[3]; + const currentX = lastPoint.x; + const currentY = lastPoint.y; + cp1x = currentX + (currentX - cp1x); + cp1y = currentY + (currentY - cp1y); + } + this.instructions.push({ action: "bezierCurveTo", data: [cp1x, cp1y, cp2x, cp2y, x, y, smoothness] }); + this._dirty = true; + return this; + } + /** + * Closes the current path by drawing a straight line back to the start. + * If the shape is already closed or there are no points in the path, this method does nothing. + * @returns The instance of the current object for chaining. + */ + closePath() { + this.instructions.push({ action: "closePath", data: [] }); + this._dirty = true; + return this; + } + ellipse(...args) { + this.instructions.push({ action: "ellipse", data: args }); + this._dirty = true; + return this; + } + lineTo(...args) { + this.instructions.push({ action: "lineTo", data: args }); + this._dirty = true; + return this; + } + moveTo(...args) { + this.instructions.push({ action: "moveTo", data: args }); + return this; + } + quadraticCurveTo(...args) { + this.instructions.push({ action: "quadraticCurveTo", data: args }); + this._dirty = true; + return this; + } + /** + * Adds a quadratic curve to the path. It uses the previous point as the control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothness - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + quadraticCurveToShort(x, y, smoothness) { + const last = this.instructions[this.instructions.length - 1]; + const lastPoint = this.getLastPoint(Point.shared); + let cpx1 = 0; + let cpy1 = 0; + if (!last || last.action !== "quadraticCurveTo") { + cpx1 = lastPoint.x; + cpy1 = lastPoint.y; + } else { + cpx1 = last.data[0]; + cpy1 = last.data[1]; + const currentX = lastPoint.x; + const currentY = lastPoint.y; + cpx1 = currentX + (currentX - cpx1); + cpy1 = currentY + (currentY - cpy1); + } + this.instructions.push({ action: "quadraticCurveTo", data: [cpx1, cpy1, x, y, smoothness] }); + this._dirty = true; + return this; + } + /** + * Draws a rectangle shape. This method adds a new rectangle path to the current drawing. + * @param x - The x-coordinate of the top-left corner of the rectangle. + * @param y - The y-coordinate of the top-left corner of the rectangle. + * @param w - The width of the rectangle. + * @param h - The height of the rectangle. + * @param transform - An optional `Matrix` object to apply a transformation to the rectangle. + * @returns The instance of the current object for chaining. + */ + rect(x, y, w, h, transform) { + this.instructions.push({ action: "rect", data: [x, y, w, h, transform] }); + this._dirty = true; + return this; + } + /** + * Draws a circle shape. This method adds a new circle path to the current drawing. + * @param x - The x-coordinate of the center of the circle. + * @param y - The y-coordinate of the center of the circle. + * @param radius - The radius of the circle. + * @param transform - An optional `Matrix` object to apply a transformation to the circle. + * @returns The instance of the current object for chaining. + */ + circle(x, y, radius, transform) { + this.instructions.push({ action: "circle", data: [x, y, radius, transform] }); + this._dirty = true; + return this; + } + roundRect(...args) { + this.instructions.push({ action: "roundRect", data: args }); + this._dirty = true; + return this; + } + poly(...args) { + this.instructions.push({ action: "poly", data: args }); + this._dirty = true; + return this; + } + regularPoly(...args) { + this.instructions.push({ action: "regularPoly", data: args }); + this._dirty = true; + return this; + } + roundPoly(...args) { + this.instructions.push({ action: "roundPoly", data: args }); + this._dirty = true; + return this; + } + roundShape(...args) { + this.instructions.push({ action: "roundShape", data: args }); + this._dirty = true; + return this; + } + filletRect(...args) { + this.instructions.push({ action: "filletRect", data: args }); + this._dirty = true; + return this; + } + chamferRect(...args) { + this.instructions.push({ action: "chamferRect", data: args }); + this._dirty = true; + return this; + } + /** + * Draws a star shape centered at a specified location. This method allows for the creation + * of stars with a variable number of points, outer radius, optional inner radius, and rotation. + * The star is drawn as a closed polygon with alternating outer and inner vertices to create the star's points. + * An optional transformation can be applied to scale, rotate, or translate the star as needed. + * @param x - The x-coordinate of the center of the star. + * @param y - The y-coordinate of the center of the star. + * @param points - The number of points of the star. + * @param radius - The outer radius of the star (distance from the center to the outer points). + * @param innerRadius - Optional. The inner radius of the star + * (distance from the center to the inner points between the outer points). + * If not provided, defaults to half of the `radius`. + * @param rotation - Optional. The rotation of the star in radians, where 0 is aligned with the y-axis. + * Defaults to 0, meaning one point is directly upward. + * @param transform - An optional `Matrix` object to apply a transformation to the star. + * This can include rotations, scaling, and translations. + * @returns The instance of the current object for chaining further drawing commands. + */ + // eslint-disable-next-line max-len + star(x, y, points, radius, innerRadius, rotation, transform) { + innerRadius = innerRadius || radius / 2; + const startAngle = -1 * Math.PI / 2 + rotation; + const len = points * 2; + const delta = Math.PI * 2 / len; + const polygon = []; + for (let i = 0; i < len; i++) { + const r = i % 2 ? innerRadius : radius; + const angle = i * delta + startAngle; + polygon.push( + x + r * Math.cos(angle), + y + r * Math.sin(angle) + ); + } + this.poly(polygon, true, transform); + return this; + } + /** + * Creates a copy of the current `GraphicsPath` instance. This method supports both shallow and deep cloning. + * A shallow clone copies the reference of the instructions array, while a deep clone creates a new array and + * copies each instruction individually, ensuring that modifications to the instructions of the cloned `GraphicsPath` + * do not affect the original `GraphicsPath` and vice versa. + * @param deep - A boolean flag indicating whether the clone should be deep. + * @returns A new `GraphicsPath` instance that is a clone of the current instance. + */ + clone(deep = false) { + const newGraphicsPath2D = new GraphicsPath(); + if (!deep) { + newGraphicsPath2D.instructions = this.instructions.slice(); + } else { + for (let i = 0; i < this.instructions.length; i++) { + const instruction = this.instructions[i]; + newGraphicsPath2D.instructions.push({ action: instruction.action, data: instruction.data.slice() }); + } + } + return newGraphicsPath2D; + } + clear() { + this.instructions.length = 0; + this._dirty = true; + return this; + } + /** + * Applies a transformation matrix to all drawing instructions within the `GraphicsPath`. + * This method enables the modification of the path's geometry according to the provided + * transformation matrix, which can include translations, rotations, scaling, and skewing. + * + * Each drawing instruction in the path is updated to reflect the transformation, + * ensuring the visual representation of the path is consistent with the applied matrix. + * + * Note: The transformation is applied directly to the coordinates and control points of the drawing instructions, + * not to the path as a whole. This means the transformation's effects are baked into the individual instructions, + * allowing for fine-grained control over the path's appearance. + * @param matrix - A `Matrix` object representing the transformation to apply. + * @returns The instance of the current object for chaining further operations. + */ + transform(matrix) { + if (matrix.isIdentity()) + return this; + const a = matrix.a; + const b = matrix.b; + const c = matrix.c; + const d = matrix.d; + const tx = matrix.tx; + const ty = matrix.ty; + let x = 0; + let y = 0; + let cpx1 = 0; + let cpy1 = 0; + let cpx2 = 0; + let cpy2 = 0; + let rx = 0; + let ry = 0; + for (let i = 0; i < this.instructions.length; i++) { + const instruction = this.instructions[i]; + const data = instruction.data; + switch (instruction.action) { + case "moveTo": + case "lineTo": + x = data[0]; + y = data[1]; + data[0] = a * x + c * y + tx; + data[1] = b * x + d * y + ty; + break; + case "bezierCurveTo": + cpx1 = data[0]; + cpy1 = data[1]; + cpx2 = data[2]; + cpy2 = data[3]; + x = data[4]; + y = data[5]; + data[0] = a * cpx1 + c * cpy1 + tx; + data[1] = b * cpx1 + d * cpy1 + ty; + data[2] = a * cpx2 + c * cpy2 + tx; + data[3] = b * cpx2 + d * cpy2 + ty; + data[4] = a * x + c * y + tx; + data[5] = b * x + d * y + ty; + break; + case "quadraticCurveTo": + cpx1 = data[0]; + cpy1 = data[1]; + x = data[2]; + y = data[3]; + data[0] = a * cpx1 + c * cpy1 + tx; + data[1] = b * cpx1 + d * cpy1 + ty; + data[2] = a * x + c * y + tx; + data[3] = b * x + d * y + ty; + break; + case "arcToSvg": + x = data[5]; + y = data[6]; + rx = data[0]; + ry = data[1]; + data[0] = a * rx + c * ry; + data[1] = b * rx + d * ry; + data[5] = a * x + c * y + tx; + data[6] = b * x + d * y + ty; + break; + case "circle": + data[4] = adjustTransform(data[3], matrix); + break; + case "rect": + data[4] = adjustTransform(data[4], matrix); + break; + case "ellipse": + data[8] = adjustTransform(data[8], matrix); + break; + case "roundRect": + data[5] = adjustTransform(data[5], matrix); + break; + case "addPath": + data[0].transform(matrix); + break; + case "poly": + data[2] = adjustTransform(data[2], matrix); + break; + default: + warn("unknown transform action", instruction.action); + break; + } + } + this._dirty = true; + return this; + } + get bounds() { + return this.shapePath.bounds; + } + /** + * Retrieves the last point from the current drawing instructions in the `GraphicsPath`. + * This method is useful for operations that depend on the path's current endpoint, + * such as connecting subsequent shapes or paths. It supports various drawing instructions, + * ensuring the last point's position is accurately determined regardless of the path's complexity. + * + * If the last instruction is a `closePath`, the method iterates backward through the instructions + * until it finds an actionable instruction that defines a point (e.g., `moveTo`, `lineTo`, + * `quadraticCurveTo`, etc.). For compound paths added via `addPath`, it recursively retrieves + * the last point from the nested path. + * @param out - A `Point` object where the last point's coordinates will be stored. + * This object is modified directly to contain the result. + * @returns The `Point` object containing the last point's coordinates. + */ + getLastPoint(out) { + let index = this.instructions.length - 1; + let lastInstruction = this.instructions[index]; + if (!lastInstruction) { + out.x = 0; + out.y = 0; + return out; + } + while (lastInstruction.action === "closePath") { + index--; + if (index < 0) { + out.x = 0; + out.y = 0; + return out; + } + lastInstruction = this.instructions[index]; + } + switch (lastInstruction.action) { + case "moveTo": + case "lineTo": + out.x = lastInstruction.data[0]; + out.y = lastInstruction.data[1]; + break; + case "quadraticCurveTo": + out.x = lastInstruction.data[2]; + out.y = lastInstruction.data[3]; + break; + case "bezierCurveTo": + out.x = lastInstruction.data[4]; + out.y = lastInstruction.data[5]; + break; + case "arc": + case "arcToSvg": + out.x = lastInstruction.data[5]; + out.y = lastInstruction.data[6]; + break; + case "addPath": + lastInstruction.data[0].getLastPoint(out); + break; + } + return out; + } + } + function adjustTransform(currentMatrix, transform) { + if (currentMatrix) { + return currentMatrix.prepend(transform); + } + return transform.clone(); + } + + "use strict"; + var __defProp$R = Object.defineProperty; + var __getOwnPropSymbols$R = Object.getOwnPropertySymbols; + var __hasOwnProp$R = Object.prototype.hasOwnProperty; + var __propIsEnum$R = Object.prototype.propertyIsEnumerable; + var __defNormalProp$R = (obj, key, value) => key in obj ? __defProp$R(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$R = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$R.call(b, prop)) + __defNormalProp$R(a, prop, b[prop]); + if (__getOwnPropSymbols$R) + for (var prop of __getOwnPropSymbols$R(b)) { + if (__propIsEnum$R.call(b, prop)) + __defNormalProp$R(a, prop, b[prop]); + } + return a; + }; + function SVGParser(svg, graphicsContext) { + if (typeof svg === "string") { + const div = document.createElement("div"); + div.innerHTML = svg.trim(); + svg = div.querySelector("svg"); + } + const session = { + context: graphicsContext, + path: new GraphicsPath() + }; + renderChildren(svg, session, null, null); + return graphicsContext; + } + function renderChildren(svg, session, fillStyle, strokeStyle) { + const children = svg.children; + const { fillStyle: f1, strokeStyle: s1 } = parseStyle(svg); + if (f1 && fillStyle) { + fillStyle = __spreadValues$R(__spreadValues$R({}, fillStyle), f1); + } else if (f1) { + fillStyle = f1; + } + if (s1 && strokeStyle) { + strokeStyle = __spreadValues$R(__spreadValues$R({}, strokeStyle), s1); + } else if (s1) { + strokeStyle = s1; + } + session.context.fillStyle = fillStyle; + session.context.strokeStyle = strokeStyle; + let x; + let y; + let x1; + let y1; + let x2; + let y2; + let cx; + let cy; + let r; + let rx; + let ry; + let points; + let pointsString; + let d; + let graphicsPath; + let width; + let height; + switch (svg.nodeName.toLowerCase()) { + case "path": + d = svg.getAttribute("d"); + graphicsPath = new GraphicsPath(d); + session.context.path(graphicsPath); + if (fillStyle) + session.context.fill(); + if (strokeStyle) + session.context.stroke(); + break; + case "circle": + cx = parseFloatAttribute(svg, "cx", 0); + cy = parseFloatAttribute(svg, "cy", 0); + r = parseFloatAttribute(svg, "r", 0); + session.context.ellipse(cx, cy, r, r); + if (fillStyle) + session.context.fill(); + if (strokeStyle) + session.context.stroke(); + break; + case "rect": + x = parseFloatAttribute(svg, "x", 0); + y = parseFloatAttribute(svg, "y", 0); + width = parseFloatAttribute(svg, "width", 0); + height = parseFloatAttribute(svg, "height", 0); + rx = parseFloatAttribute(svg, "rx", 0); + ry = parseFloatAttribute(svg, "ry", 0); + if (rx || ry) { + session.context.roundRect(x, y, width, height, rx || ry); + } else { + session.context.rect(x, y, width, height); + } + if (fillStyle) + session.context.fill(); + if (strokeStyle) + session.context.stroke(); + break; + case "ellipse": + cx = parseFloatAttribute(svg, "cx", 0); + cy = parseFloatAttribute(svg, "cy", 0); + rx = parseFloatAttribute(svg, "rx", 0); + ry = parseFloatAttribute(svg, "ry", 0); + session.context.beginPath(); + session.context.ellipse(cx, cy, rx, ry); + if (fillStyle) + session.context.fill(); + if (strokeStyle) + session.context.stroke(); + break; + case "line": + x1 = parseFloatAttribute(svg, "x1", 0); + y1 = parseFloatAttribute(svg, "y1", 0); + x2 = parseFloatAttribute(svg, "x2", 0); + y2 = parseFloatAttribute(svg, "y2", 0); + session.context.beginPath(); + session.context.moveTo(x1, y1); + session.context.lineTo(x2, y2); + if (strokeStyle) + session.context.stroke(); + break; + case "polygon": + pointsString = svg.getAttribute("points"); + points = pointsString.match(/\d+/g).map((n) => parseInt(n, 10)); + session.context.poly(points, true); + if (fillStyle) + session.context.fill(); + if (strokeStyle) + session.context.stroke(); + break; + case "polyline": + pointsString = svg.getAttribute("points"); + points = pointsString.match(/\d+/g).map((n) => parseInt(n, 10)); + session.context.poly(points, false); + if (strokeStyle) + session.context.stroke(); + break; + case "g": + case "svg": + break; + default: { + console.info(`[SVG parser] <${svg.nodeName}> elements unsupported`); + break; + } + } + for (let i = 0; i < children.length; i++) { + renderChildren(children[i], session, fillStyle, strokeStyle); + } + } + function parseFloatAttribute(svg, id, defaultValue) { + const value = svg.getAttribute(id); + return value ? Number(value) : defaultValue; + } + function parseStyle(svg) { + const style = svg.getAttribute("style"); + const strokeStyle = {}; + const fillStyle = {}; + let useFill = false; + let useStroke = false; + if (style) { + const styleParts = style.split(";"); + for (let i = 0; i < styleParts.length; i++) { + const stylePart = styleParts[i]; + const [key, value] = stylePart.split(":"); + switch (key) { + case "stroke": + if (value !== "none") { + strokeStyle.color = Color.shared.setValue(value).toNumber(); + useStroke = true; + } + break; + case "stroke-width": + strokeStyle.width = Number(value); + break; + case "fill": + if (value !== "none") { + useFill = true; + fillStyle.color = Color.shared.setValue(value).toNumber(); + } + break; + case "fill-opacity": + fillStyle.alpha = Number(value); + break; + case "stroke-opacity": + strokeStyle.alpha = Number(value); + break; + case "opacity": + fillStyle.alpha = Number(value); + strokeStyle.alpha = Number(value); + break; + } + } + } else { + const stroke = svg.getAttribute("stroke"); + if (stroke && stroke !== "none") { + useStroke = true; + strokeStyle.color = Color.shared.setValue(stroke).toNumber(); + strokeStyle.width = parseFloatAttribute(svg, "stroke-width", 1); + } + const fill = svg.getAttribute("fill"); + if (fill && fill !== "none") { + useFill = true; + fillStyle.color = Color.shared.setValue(fill).toNumber(); + } + } + return { + strokeStyle: useStroke ? strokeStyle : null, + fillStyle: useFill ? fillStyle : null + }; + } + + "use strict"; + var __defProp$Q = Object.defineProperty; + var __getOwnPropSymbols$Q = Object.getOwnPropertySymbols; + var __hasOwnProp$Q = Object.prototype.hasOwnProperty; + var __propIsEnum$Q = Object.prototype.propertyIsEnumerable; + var __defNormalProp$Q = (obj, key, value) => key in obj ? __defProp$Q(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$Q = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$Q.call(b, prop)) + __defNormalProp$Q(a, prop, b[prop]); + if (__getOwnPropSymbols$Q) + for (var prop of __getOwnPropSymbols$Q(b)) { + if (__propIsEnum$Q.call(b, prop)) + __defNormalProp$Q(a, prop, b[prop]); + } + return a; + }; + var __objRest$h = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$Q.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$Q) + for (var prop of __getOwnPropSymbols$Q(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$Q.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + function isColorLike(value) { + return Color.isColorLike(value); + } + function isFillPattern(value) { + return value instanceof FillPattern; + } + function isFillGradient(value) { + return value instanceof FillGradient; + } + function handleColorLike(fill, value, defaultStyle) { + const temp = Color.shared.setValue(value != null ? value : 0); + fill.color = temp.toNumber(); + fill.alpha = temp.alpha === 1 ? defaultStyle.alpha : temp.alpha; + fill.texture = Texture.WHITE; + return __spreadValues$Q(__spreadValues$Q({}, defaultStyle), fill); + } + function handleFillPattern(fill, value, defaultStyle) { + fill.fill = value; + fill.color = 16777215; + fill.texture = value.texture; + fill.matrix = value.transform; + return __spreadValues$Q(__spreadValues$Q({}, defaultStyle), fill); + } + function handleFillGradient(fill, value, defaultStyle) { + value.buildLinearGradient(); + fill.fill = value; + fill.color = 16777215; + fill.texture = value.texture; + fill.matrix = value.transform; + return __spreadValues$Q(__spreadValues$Q({}, defaultStyle), fill); + } + function handleFillObject(value, defaultStyle) { + var _a; + const style = __spreadValues$Q(__spreadValues$Q({}, defaultStyle), value); + if (style.texture) { + if (style.texture !== Texture.WHITE) { + const m = ((_a = style.matrix) == null ? void 0 : _a.invert()) || new Matrix(); + m.scale(1 / style.texture.frame.width, 1 / style.texture.frame.height); + style.matrix = m; + } + const sourceStyle = style.texture.source.style; + if (sourceStyle.addressMode === "clamp-to-edge") { + sourceStyle.addressMode = "repeat"; + } + } + const color = Color.shared.setValue(style.color); + style.alpha *= color.alpha; + style.color = color.toNumber(); + style.matrix = style.matrix ? style.matrix.clone() : null; + return style; + } + function toFillStyle(value, defaultStyle) { + if (value === void 0 || value === null) { + return null; + } + const fill = {}; + const objectStyle = value; + if (isColorLike(value)) { + return handleColorLike(fill, value, defaultStyle); + } else if (isFillPattern(value)) { + return handleFillPattern(fill, value, defaultStyle); + } else if (isFillGradient(value)) { + return handleFillGradient(fill, value, defaultStyle); + } else if (objectStyle.fill && isFillPattern(objectStyle.fill)) { + return handleFillPattern(objectStyle, objectStyle.fill, defaultStyle); + } else if (objectStyle.fill && isFillGradient(objectStyle.fill)) { + return handleFillGradient(objectStyle, objectStyle.fill, defaultStyle); + } + return handleFillObject(objectStyle, defaultStyle); + } + function toStrokeStyle(value, defaultStyle) { + const _a = defaultStyle, { width, alignment, miterLimit, cap, join } = _a, rest = __objRest$h(_a, ["width", "alignment", "miterLimit", "cap", "join"]); + const fill = toFillStyle(value, rest); + if (!fill) { + return null; + } + return __spreadValues$Q({ + width, + alignment, + miterLimit, + cap, + join + }, fill); + } + + "use strict"; + var __defProp$P = Object.defineProperty; + var __getOwnPropSymbols$P = Object.getOwnPropertySymbols; + var __hasOwnProp$P = Object.prototype.hasOwnProperty; + var __propIsEnum$P = Object.prototype.propertyIsEnumerable; + var __defNormalProp$P = (obj, key, value) => key in obj ? __defProp$P(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$P = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$P.call(b, prop)) + __defNormalProp$P(a, prop, b[prop]); + if (__getOwnPropSymbols$P) + for (var prop of __getOwnPropSymbols$P(b)) { + if (__propIsEnum$P.call(b, prop)) + __defNormalProp$P(a, prop, b[prop]); + } + return a; + }; + const tmpPoint = new Point(); + const tempMatrix$2 = new Matrix(); + const _GraphicsContext = class _GraphicsContext extends EventEmitter { + constructor() { + super(...arguments); + this.uid = uid("graphicsContext"); + this.dirty = true; + this.batchMode = "auto"; + this.instructions = []; + this._activePath = new GraphicsPath(); + this._transform = new Matrix(); + this._fillStyle = __spreadValues$P({}, _GraphicsContext.defaultFillStyle); + this._strokeStyle = __spreadValues$P({}, _GraphicsContext.defaultStrokeStyle); + this._stateStack = []; + this._tick = 0; + this._bounds = new Bounds(); + this._boundsDirty = true; + } + /** + * Creates a new GraphicsContext object that is a clone of this instance, copying all properties, + * including the current drawing state, transformations, styles, and instructions. + * @returns A new GraphicsContext instance with the same properties and state as this one. + */ + clone() { + const clone = new _GraphicsContext(); + clone.batchMode = this.batchMode; + clone.instructions = this.instructions.slice(); + clone._activePath = this._activePath.clone(); + clone._transform = this._transform.clone(); + clone._fillStyle = __spreadValues$P({}, this._fillStyle); + clone._strokeStyle = __spreadValues$P({}, this._strokeStyle); + clone._stateStack = this._stateStack.slice(); + clone._bounds = this._bounds.clone(); + clone._boundsDirty = true; + return clone; + } + /** + * The current fill style of the graphics context. This can be a color, gradient, pattern, or a more complex style defined by a FillStyle object. + */ + get fillStyle() { + return this._fillStyle; + } + set fillStyle(value) { + this._fillStyle = toFillStyle(value, _GraphicsContext.defaultFillStyle); + } + /** + * The current stroke style of the graphics context. Similar to fill styles, stroke styles can encompass colors, gradients, patterns, or more detailed configurations via a StrokeStyle object. + */ + get strokeStyle() { + return this._strokeStyle; + } + set strokeStyle(value) { + this._strokeStyle = toStrokeStyle(value, _GraphicsContext.defaultStrokeStyle); + } + /** + * Sets the current fill style of the graphics context. The fill style can be a color, gradient, + * pattern, or a more complex style defined by a FillStyle object. + * @param style - The fill style to apply. This can be a simple color, a gradient or pattern object, + * or a FillStyle or ConvertedFillStyle object. + * @returns The instance of the current GraphicsContext for method chaining. + */ + setFillStyle(style) { + this._fillStyle = toFillStyle(style, _GraphicsContext.defaultFillStyle); + return this; + } + /** + * Sets the current stroke style of the graphics context. Similar to fill styles, stroke styles can + * encompass colors, gradients, patterns, or more detailed configurations via a StrokeStyle object. + * @param style - The stroke style to apply. Can be defined as a color, a gradient or pattern, + * or a StrokeStyle or ConvertedStrokeStyle object. + * @returns The instance of the current GraphicsContext for method chaining. + */ + setStrokeStyle(style) { + this._strokeStyle = toFillStyle(style, _GraphicsContext.defaultStrokeStyle); + return this; + } + texture(texture, tint, dx, dy, dw, dh) { + this.instructions.push({ + action: "texture", + data: { + image: texture, + dx: dx || 0, + dy: dy || 0, + dw: dw || texture.frame.width, + dh: dh || texture.frame.height, + transform: this._transform.clone(), + alpha: this._fillStyle.alpha, + style: tint ? Color.shared.setValue(tint).toNumber() : 16777215 + } + }); + this.onUpdate(); + return this; + } + /** + * Resets the current path. Any previous path and its commands are discarded and a new path is + * started. This is typically called before beginning a new shape or series of drawing commands. + * @returns The instance of the current GraphicsContext for method chaining. + */ + beginPath() { + this._activePath = new GraphicsPath(); + return this; + } + fill(style, alpha) { + let path; + const lastInstruction = this.instructions[this.instructions.length - 1]; + if (this._tick === 0 && lastInstruction && lastInstruction.action === "stroke") { + path = lastInstruction.data.path; + } else { + path = this._activePath.clone(); + } + if (!path) + return this; + if (style != null) { + if (alpha !== void 0 && typeof style === "number") { + deprecation(v8_0_0, "GraphicsContext.fill(color, alpha) is deprecated, use GraphicsContext.fill({ color, alpha }) instead"); + style = { color: style, alpha }; + } + this._fillStyle = toFillStyle(style, _GraphicsContext.defaultFillStyle); + } + this.instructions.push({ + action: "fill", + // TODO copy fill style! + data: { style: this.fillStyle, path } + }); + this.onUpdate(); + this._initNextPathLocation(); + this._tick = 0; + return this; + } + _initNextPathLocation() { + const { x, y } = this._activePath.getLastPoint(Point.shared); + this._activePath.clear(); + this._activePath.moveTo(x, y); + } + /** + * Strokes the current path with the current stroke style. This method can take an optional + * FillInput parameter to define the stroke's appearance, including its color, width, and other properties. + * @param style - (Optional) The stroke style to apply. Can be defined as a simple color or a more complex style object. If omitted, uses the current stroke style. + * @returns The instance of the current GraphicsContext for method chaining. + */ + stroke(style) { + let path; + const lastInstruction = this.instructions[this.instructions.length - 1]; + if (this._tick === 0 && lastInstruction && lastInstruction.action === "fill") { + path = lastInstruction.data.path; + } else { + path = this._activePath.clone(); + } + if (!path) + return this; + if (style != null) { + this._strokeStyle = toStrokeStyle(style, _GraphicsContext.defaultStrokeStyle); + } + this.instructions.push({ + action: "stroke", + // TODO copy fill style! + data: { style: this.strokeStyle, path } + }); + this.onUpdate(); + this._initNextPathLocation(); + this._tick = 0; + return this; + } + /** + * Applies a cutout to the last drawn shape. This is used to create holes or complex shapes by + * subtracting a path from the previously drawn path. If a hole is not completely in a shape, it will + * fail to cut correctly! + * @returns The instance of the current GraphicsContext for method chaining. + */ + cut() { + for (let i = 0; i < 2; i++) { + const lastInstruction = this.instructions[this.instructions.length - 1 - i]; + const holePath = this._activePath.clone(); + if (lastInstruction) { + if (lastInstruction.action === "stroke" || lastInstruction.action === "fill") { + if (lastInstruction.data.hole) { + lastInstruction.data.hole.addPath(holePath); + } else { + lastInstruction.data.hole = holePath; + break; + } + } + } + } + this._initNextPathLocation(); + return this; + } + /** + * Adds an arc to the current path, which is centered at (x, y) with the specified radius, + * starting and ending angles, and direction. + * @param x - The x-coordinate of the arc's center. + * @param y - The y-coordinate of the arc's center. + * @param radius - The arc's radius. + * @param startAngle - The starting angle, in radians. + * @param endAngle - The ending angle, in radians. + * @param counterclockwise - (Optional) Specifies whether the arc is drawn counterclockwise (true) or clockwise (false). Defaults to false. + * @returns The instance of the current GraphicsContext for method chaining. + */ + arc(x, y, radius, startAngle, endAngle, counterclockwise) { + this._tick++; + const t = this._transform; + this._activePath.arc( + t.a * x + t.c * y + t.tx, + t.b * x + t.d * y + t.ty, + radius, + startAngle, + endAngle, + counterclockwise + ); + return this; + } + /** + * Adds an arc to the current path with the given control points and radius, connected to the previous point + * by a straight line if necessary. + * @param x1 - The x-coordinate of the first control point. + * @param y1 - The y-coordinate of the first control point. + * @param x2 - The x-coordinate of the second control point. + * @param y2 - The y-coordinate of the second control point. + * @param radius - The arc's radius. + * @returns The instance of the current GraphicsContext for method chaining. + */ + arcTo(x1, y1, x2, y2, radius) { + this._tick++; + const t = this._transform; + this._activePath.arcTo( + t.a * x1 + t.c * y1 + t.tx, + t.b * x1 + t.d * y1 + t.ty, + t.a * x2 + t.c * y2 + t.tx, + t.b * x2 + t.d * y2 + t.ty, + radius + ); + return this; + } + /** + * Adds an SVG-style arc to the path, allowing for elliptical arcs based on the SVG spec. + * @param rx - The x-radius of the ellipse. + * @param ry - The y-radius of the ellipse. + * @param xAxisRotation - The rotation of the ellipse's x-axis relative + * to the x-axis of the coordinate system, in degrees. + * @param largeArcFlag - Determines if the arc should be greater than or less than 180 degrees. + * @param sweepFlag - Determines if the arc should be swept in a positive angle direction. + * @param x - The x-coordinate of the arc's end point. + * @param y - The y-coordinate of the arc's end point. + * @returns The instance of the current object for chaining. + */ + arcToSvg(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) { + this._tick++; + const t = this._transform; + this._activePath.arcToSvg( + rx, + ry, + xAxisRotation, + // should we rotate this with transform?? + largeArcFlag, + sweepFlag, + t.a * x + t.c * y + t.tx, + t.b * x + t.d * y + t.ty + ); + return this; + } + /** + * Adds a cubic Bezier curve to the path. + * It requires three points: the first two are control points and the third one is the end point. + * The starting point is the last point in the current path. + * @param cp1x - The x-coordinate of the first control point. + * @param cp1y - The y-coordinate of the first control point. + * @param cp2x - The x-coordinate of the second control point. + * @param cp2y - The y-coordinate of the second control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothness - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y, smoothness) { + this._tick++; + const t = this._transform; + this._activePath.bezierCurveTo( + t.a * cp1x + t.c * cp1y + t.tx, + t.b * cp1x + t.d * cp1y + t.ty, + t.a * cp2x + t.c * cp2y + t.tx, + t.b * cp2x + t.d * cp2y + t.ty, + t.a * x + t.c * y + t.tx, + t.b * x + t.d * y + t.ty, + smoothness + ); + return this; + } + /** + * Closes the current path by drawing a straight line back to the start. + * If the shape is already closed or there are no points in the path, this method does nothing. + * @returns The instance of the current object for chaining. + */ + closePath() { + var _a; + this._tick++; + (_a = this._activePath) == null ? void 0 : _a.closePath(); + return this; + } + /** + * Draws an ellipse at the specified location and with the given x and y radii. + * An optional transformation can be applied, allowing for rotation, scaling, and translation. + * @param x - The x-coordinate of the center of the ellipse. + * @param y - The y-coordinate of the center of the ellipse. + * @param radiusX - The horizontal radius of the ellipse. + * @param radiusY - The vertical radius of the ellipse. + * @returns The instance of the current object for chaining. + */ + ellipse(x, y, radiusX, radiusY) { + this._tick++; + this._activePath.ellipse(x, y, radiusX, radiusY, this._transform.clone()); + return this; + } + /** + * Draws a circle shape. This method adds a new circle path to the current drawing. + * @param x - The x-coordinate of the center of the circle. + * @param y - The y-coordinate of the center of the circle. + * @param radius - The radius of the circle. + * @returns The instance of the current object for chaining. + */ + circle(x, y, radius) { + this._tick++; + this._activePath.circle(x, y, radius, this._transform.clone()); + return this; + } + /** + * Adds another `GraphicsPath` to this path, optionally applying a transformation. + * @param path - The `GraphicsPath` to add. + * @returns The instance of the current object for chaining. + */ + path(path) { + this._tick++; + this._activePath.addPath(path, this._transform.clone()); + return this; + } + /** + * Connects the current point to a new point with a straight line. This method updates the current path. + * @param x - The x-coordinate of the new point to connect to. + * @param y - The y-coordinate of the new point to connect to. + * @returns The instance of the current object for chaining. + */ + lineTo(x, y) { + this._tick++; + const t = this._transform; + this._activePath.lineTo( + t.a * x + t.c * y + t.tx, + t.b * x + t.d * y + t.ty + ); + return this; + } + /** + * Sets the starting point for a new sub-path. Any subsequent drawing commands are considered part of this path. + * @param x - The x-coordinate for the starting point. + * @param y - The y-coordinate for the starting point. + * @returns The instance of the current object for chaining. + */ + moveTo(x, y) { + this._tick++; + const t = this._transform; + const instructions = this._activePath.instructions; + const transformedX = t.a * x + t.c * y + t.tx; + const transformedY = t.b * x + t.d * y + t.ty; + if (instructions.length === 1 && instructions[0].action === "moveTo") { + instructions[0].data[0] = transformedX; + instructions[0].data[1] = transformedY; + return this; + } + this._activePath.moveTo( + transformedX, + transformedY + ); + return this; + } + /** + * Adds a quadratic curve to the path. It requires two points: the control point and the end point. + * The starting point is the last point in the current path. + * @param cpx - The x-coordinate of the control point. + * @param cpy - The y-coordinate of the control point. + * @param x - The x-coordinate of the end point. + * @param y - The y-coordinate of the end point. + * @param smoothness - Optional parameter to adjust the smoothness of the curve. + * @returns The instance of the current object for chaining. + */ + quadraticCurveTo(cpx, cpy, x, y, smoothness) { + this._tick++; + const t = this._transform; + this._activePath.quadraticCurveTo( + t.a * cpx + t.c * cpy + t.tx, + t.b * cpx + t.d * cpy + t.ty, + t.a * x + t.c * y + t.tx, + t.b * x + t.d * y + t.ty, + smoothness + ); + return this; + } + /** + * Draws a rectangle shape. This method adds a new rectangle path to the current drawing. + * @param x - The x-coordinate of the top-left corner of the rectangle. + * @param y - The y-coordinate of the top-left corner of the rectangle. + * @param w - The width of the rectangle. + * @param h - The height of the rectangle. + * @returns The instance of the current object for chaining. + */ + rect(x, y, w, h) { + this._tick++; + this._activePath.rect(x, y, w, h, this._transform.clone()); + return this; + } + /** + * Draws a rectangle with rounded corners. + * The corner radius can be specified to determine how rounded the corners should be. + * An optional transformation can be applied, which allows for rotation, scaling, and translation of the rectangle. + * @param x - The x-coordinate of the top-left corner of the rectangle. + * @param y - The y-coordinate of the top-left corner of the rectangle. + * @param w - The width of the rectangle. + * @param h - The height of the rectangle. + * @param radius - The radius of the rectangle's corners. If not specified, corners will be sharp. + * @returns The instance of the current object for chaining. + */ + roundRect(x, y, w, h, radius) { + this._tick++; + this._activePath.roundRect(x, y, w, h, radius, this._transform.clone()); + return this; + } + /** + * Draws a polygon shape by specifying a sequence of points. This method allows for the creation of complex polygons, + * which can be both open and closed. An optional transformation can be applied, enabling the polygon to be scaled, + * rotated, or translated as needed. + * @param points - An array of numbers, or an array of PointData objects eg [{x,y}, {x,y}, {x,y}] + * representing the x and y coordinates, of the polygon's vertices, in sequence. + * @param close - A boolean indicating whether to close the polygon path. True by default. + */ + poly(points, close) { + this._tick++; + this._activePath.poly(points, close, this._transform.clone()); + return this; + } + /** + * Draws a regular polygon with a specified number of sides. All sides and angles are equal. + * @param x - The x-coordinate of the center of the polygon. + * @param y - The y-coordinate of the center of the polygon. + * @param radius - The radius of the circumscribed circle of the polygon. + * @param sides - The number of sides of the polygon. Must be 3 or more. + * @param rotation - The rotation angle of the polygon, in radians. Zero by default. + * @param transform - An optional `Matrix` object to apply a transformation to the polygon. + * @returns The instance of the current object for chaining. + */ + regularPoly(x, y, radius, sides, rotation = 0, transform) { + this._tick++; + this._activePath.regularPoly(x, y, radius, sides, rotation, transform); + return this; + } + /** + * Draws a polygon with rounded corners. + * Similar to `regularPoly` but with the ability to round the corners of the polygon. + * @param x - The x-coordinate of the center of the polygon. + * @param y - The y-coordinate of the center of the polygon. + * @param radius - The radius of the circumscribed circle of the polygon. + * @param sides - The number of sides of the polygon. Must be 3 or more. + * @param corner - The radius of the rounding of the corners. + * @param rotation - The rotation angle of the polygon, in radians. Zero by default. + * @returns The instance of the current object for chaining. + */ + roundPoly(x, y, radius, sides, corner, rotation) { + this._tick++; + this._activePath.roundPoly(x, y, radius, sides, corner, rotation); + return this; + } + /** + * Draws a shape with rounded corners. This function supports custom radius for each corner of the shape. + * Optionally, corners can be rounded using a quadratic curve instead of an arc, providing a different aesthetic. + * @param points - An array of `RoundedPoint` representing the corners of the shape to draw. + * A minimum of 3 points is required. + * @param radius - The default radius for the corners. + * This radius is applied to all corners unless overridden in `points`. + * @param useQuadratic - If set to true, rounded corners are drawn using a quadraticCurve + * method instead of an arc method. Defaults to false. + * @param smoothness - Specifies the smoothness of the curve when `useQuadratic` is true. + * Higher values make the curve smoother. + * @returns The instance of the current object for chaining. + */ + roundShape(points, radius, useQuadratic, smoothness) { + this._tick++; + this._activePath.roundShape(points, radius, useQuadratic, smoothness); + return this; + } + /** + * Draw Rectangle with fillet corners. This is much like rounded rectangle + * however it support negative numbers as well for the corner radius. + * @param x - Upper left corner of rect + * @param y - Upper right corner of rect + * @param width - Width of rect + * @param height - Height of rect + * @param fillet - accept negative or positive values + */ + filletRect(x, y, width, height, fillet) { + this._tick++; + this._activePath.filletRect(x, y, width, height, fillet); + return this; + } + /** + * Draw Rectangle with chamfer corners. These are angled corners. + * @param x - Upper left corner of rect + * @param y - Upper right corner of rect + * @param width - Width of rect + * @param height - Height of rect + * @param chamfer - non-zero real number, size of corner cutout + * @param transform + */ + chamferRect(x, y, width, height, chamfer, transform) { + this._tick++; + this._activePath.chamferRect(x, y, width, height, chamfer, transform); + return this; + } + /** + * Draws a star shape centered at a specified location. This method allows for the creation + * of stars with a variable number of points, outer radius, optional inner radius, and rotation. + * The star is drawn as a closed polygon with alternating outer and inner vertices to create the star's points. + * An optional transformation can be applied to scale, rotate, or translate the star as needed. + * @param x - The x-coordinate of the center of the star. + * @param y - The y-coordinate of the center of the star. + * @param points - The number of points of the star. + * @param radius - The outer radius of the star (distance from the center to the outer points). + * @param innerRadius - Optional. The inner radius of the star + * (distance from the center to the inner points between the outer points). + * If not provided, defaults to half of the `radius`. + * @param rotation - Optional. The rotation of the star in radians, where 0 is aligned with the y-axis. + * Defaults to 0, meaning one point is directly upward. + * @returns The instance of the current object for chaining further drawing commands. + */ + star(x, y, points, radius, innerRadius = 0, rotation = 0) { + this._tick++; + this._activePath.star(x, y, points, radius, innerRadius, rotation, this._transform.clone()); + return this; + } + /** + * Parses and renders an SVG string into the graphics context. This allows for complex shapes and paths + * defined in SVG format to be drawn within the graphics context. + * @param svg - The SVG string to be parsed and rendered. + */ + svg(svg) { + this._tick++; + SVGParser(svg, this); + return this; + } + /** + * Restores the most recently saved graphics state by popping the top of the graphics state stack. + * This includes transformations, fill styles, and stroke styles. + */ + restore() { + const state = this._stateStack.pop(); + if (state) { + this._transform = state.transform; + this._fillStyle = state.fillStyle; + this._strokeStyle = state.strokeStyle; + } + return this; + } + /** Saves the current graphics state, including transformations, fill styles, and stroke styles, onto a stack. */ + save() { + this._stateStack.push({ + transform: this._transform.clone(), + fillStyle: __spreadValues$P({}, this._fillStyle), + strokeStyle: __spreadValues$P({}, this._strokeStyle) + }); + return this; + } + /** + * Returns the current transformation matrix of the graphics context. + * @returns The current transformation matrix. + */ + getTransform() { + return this._transform; + } + /** + * Resets the current transformation matrix to the identity matrix, effectively removing any transformations (rotation, scaling, translation) previously applied. + * @returns The instance of the current GraphicsContext for method chaining. + */ + resetTransform() { + this._transform.identity(); + return this; + } + /** + * Applies a rotation transformation to the graphics context around the current origin. + * @param angle - The angle of rotation in radians. + * @returns The instance of the current GraphicsContext for method chaining. + */ + rotate(angle) { + this._transform.rotate(angle); + return this; + } + /** + * Applies a scaling transformation to the graphics context, scaling drawings by x horizontally and by y vertically. + * @param x - The scale factor in the horizontal direction. + * @param y - (Optional) The scale factor in the vertical direction. If not specified, the x value is used for both directions. + * @returns The instance of the current GraphicsContext for method chaining. + */ + scale(x, y = x) { + this._transform.scale(x, y); + return this; + } + setTransform(a, b, c, d, dx, dy) { + if (a instanceof Matrix) { + this._transform.set(a.a, a.b, a.c, a.d, a.tx, a.ty); + return this; + } + this._transform.set(a, b, c, d, dx, dy); + return this; + } + transform(a, b, c, d, dx, dy) { + if (a instanceof Matrix) { + this._transform.append(a); + return this; + } + tempMatrix$2.set(a, b, c, d, dx, dy); + this._transform.append(tempMatrix$2); + return this; + } + /** + * Applies a translation transformation to the graphics context, moving the origin by the specified amounts. + * @param x - The amount to translate in the horizontal direction. + * @param y - (Optional) The amount to translate in the vertical direction. If not specified, the x value is used for both directions. + * @returns The instance of the current GraphicsContext for method chaining. + */ + translate(x, y = x) { + this._transform.translate(x, y); + return this; + } + /** + * Clears all drawing commands from the graphics context, effectively resetting it. This includes clearing the path, + * and optionally resetting transformations to the identity matrix. + * @returns The instance of the current GraphicsContext for method chaining. + */ + clear() { + this._activePath.clear(); + this.instructions.length = 0; + this.resetTransform(); + this.onUpdate(); + return this; + } + onUpdate() { + if (this.dirty) + return; + this.emit("update", this, 16); + this.dirty = true; + this._boundsDirty = true; + } + /** The bounds of the graphic shape. */ + get bounds() { + if (!this._boundsDirty) + return this._bounds; + const bounds = this._bounds; + bounds.clear(); + for (let i = 0; i < this.instructions.length; i++) { + const instruction = this.instructions[i]; + const action = instruction.action; + if (action === "fill") { + const data = instruction.data; + bounds.addBounds(data.path.bounds); + } else if (action === "texture") { + const data = instruction.data; + bounds.addFrame(data.dx, data.dy, data.dx + data.dw, data.dy + data.dh, data.transform); + } + if (action === "stroke") { + const data = instruction.data; + const padding = data.style.width / 2; + const _bounds = data.path.bounds; + bounds.addFrame( + _bounds.minX - padding, + _bounds.minY - padding, + _bounds.maxX + padding, + _bounds.maxY + padding + ); + } + } + return bounds; + } + /** + * Check to see if a point is contained within this geometry. + * @param point - Point to check if it's contained. + * @returns {boolean} `true` if the point is contained within geometry. + */ + containsPoint(point) { + var _a; + if (!this.bounds.containsPoint(point.x, point.y)) + return false; + const instructions = this.instructions; + let hasHit = false; + for (let k = 0; k < instructions.length; k++) { + const instruction = instructions[k]; + const data = instruction.data; + const path = data.path; + if (!instruction.action || !path) + continue; + const style = data.style; + const shapes = path.shapePath.shapePrimitives; + for (let i = 0; i < shapes.length; i++) { + const shape = shapes[i].shape; + if (!style || !shape) + continue; + const transform = shapes[i].transform; + const transformedPoint = transform ? transform.applyInverse(point, tmpPoint) : point; + if (instruction.action === "fill") { + hasHit = shape.contains(transformedPoint.x, transformedPoint.y); + } else { + hasHit = shape.strokeContains(transformedPoint.x, transformedPoint.y, style.width); + } + const holes = data.hole; + if (holes) { + const holeShapes = (_a = holes.shapePath) == null ? void 0 : _a.shapePrimitives; + if (holeShapes) { + for (let j = 0; j < holeShapes.length; j++) { + if (holeShapes[j].shape.contains(transformedPoint.x, transformedPoint.y)) { + hasHit = false; + } + } + } + } + if (hasHit) { + return true; + } + } + } + return hasHit; + } + /** + * Destroys the GraphicsData object. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the fill/stroke style? + * @param {boolean} [options.textureSource=false] - Should it destroy the texture source of the fill/stroke style? + */ + destroy(options = false) { + this._stateStack.length = 0; + this._transform = null; + this.emit("destroy", this); + this.removeAllListeners(); + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + if (this._fillStyle.texture) { + this._fillStyle.texture.destroy(destroyTextureSource); + } + if (this._strokeStyle.texture) { + this._strokeStyle.texture.destroy(destroyTextureSource); + } + } + this._fillStyle = null; + this._strokeStyle = null; + this.instructions = null; + this._activePath = null; + this._bounds = null; + this._stateStack = null; + this.customShader = null; + this._transform = null; + } + }; + /** The default fill style to use when none is provided. */ + _GraphicsContext.defaultFillStyle = { + /** The color to use for the fill. */ + color: 16777215, + /** The alpha value to use for the fill. */ + alpha: 1, + /** The texture to use for the fill. */ + texture: Texture.WHITE, + /** The matrix to apply. */ + matrix: null, + /** The fill pattern to use. */ + fill: null + }; + /** The default stroke style to use when none is provided. */ + _GraphicsContext.defaultStrokeStyle = { + /** The width of the stroke. */ + width: 1, + /** The color to use for the stroke. */ + color: 16777215, + /** The alpha value to use for the stroke. */ + alpha: 1, + /** The alignment of the stroke. */ + alignment: 0.5, + /** The miter limit to use. */ + miterLimit: 10, + /** The line cap style to use. */ + cap: "butt", + /** The line join style to use. */ + join: "miter", + /** The texture to use for the fill. */ + texture: Texture.WHITE, + /** The matrix to apply. */ + matrix: null, + /** The fill pattern to use. */ + fill: null + }; + let GraphicsContext = _GraphicsContext; + + "use strict"; + const valuesToIterateForKeys = [ + "align", + "breakWords", + "cssOverrides", + "fontFamily", + "fontSize", + "fontStyle", + "fontVariant", + "fontWeight", + "leading", + "letterSpacing", + "lineHeight", + "padding", + "textBaseline", + "trim", + "whiteSpace", + "wordWrap", + "wordWrapWidth" + ]; + function generateTextStyleKey(style) { + const key = []; + let index = 0; + for (let i = 0; i < valuesToIterateForKeys.length; i++) { + const prop = `_${valuesToIterateForKeys[i]}`; + key[index++] = style[prop]; + } + index = addFillStyleKey(style._fill, key, index); + index = addStokeStyleKey(style._stroke, key, index); + index = addDropShadowKey(style.dropShadow, key, index); + return key.join("-"); + } + function addFillStyleKey(fillStyle, key, index) { + var _a; + if (!fillStyle) + return index; + key[index++] = fillStyle.color; + key[index++] = fillStyle.alpha; + key[index++] = (_a = fillStyle.fill) == null ? void 0 : _a.styleKey; + return index; + } + function addStokeStyleKey(strokeStyle, key, index) { + if (!strokeStyle) + return index; + index = addFillStyleKey(strokeStyle, key, index); + key[index++] = strokeStyle.width; + key[index++] = strokeStyle.alignment; + key[index++] = strokeStyle.cap; + key[index++] = strokeStyle.join; + key[index++] = strokeStyle.miterLimit; + return index; + } + function addDropShadowKey(dropShadow, key, index) { + if (!dropShadow) + return index; + key[index++] = dropShadow.alpha; + key[index++] = dropShadow.angle; + key[index++] = dropShadow.blur; + key[index++] = dropShadow.distance; + key[index++] = Color.shared.setValue(dropShadow.color).toNumber(); + return index; + } + + "use strict"; + var __defProp$O = Object.defineProperty; + var __defProps$j = Object.defineProperties; + var __getOwnPropDescs$j = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$O = Object.getOwnPropertySymbols; + var __hasOwnProp$O = Object.prototype.hasOwnProperty; + var __propIsEnum$O = Object.prototype.propertyIsEnumerable; + var __defNormalProp$O = (obj, key, value) => key in obj ? __defProp$O(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$O = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$O.call(b, prop)) + __defNormalProp$O(a, prop, b[prop]); + if (__getOwnPropSymbols$O) + for (var prop of __getOwnPropSymbols$O(b)) { + if (__propIsEnum$O.call(b, prop)) + __defNormalProp$O(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$j = (a, b) => __defProps$j(a, __getOwnPropDescs$j(b)); + const _TextStyle = class _TextStyle extends EventEmitter { + constructor(style = {}) { + super(); + convertV7Tov8Style(style); + const fullStyle = __spreadValues$O(__spreadValues$O({}, _TextStyle.defaultTextStyle), style); + for (const key in fullStyle) { + const thisKey = key; + this[thisKey] = fullStyle[key]; + } + this.update(); + } + /** + * Alignment for multiline text, does not affect single line text. + * @member {'left'|'center'|'right'|'justify'} + */ + get align() { + return this._align; + } + set align(value) { + this._align = value; + this.update(); + } + /** Indicates if lines can be wrapped within words, it needs wordWrap to be set to true. */ + get breakWords() { + return this._breakWords; + } + set breakWords(value) { + this._breakWords = value; + this.update(); + } + /** Set a drop shadow for the text. */ + get dropShadow() { + return this._dropShadow; + } + set dropShadow(value) { + if (value !== null && typeof value === "object") { + this._dropShadow = this._createProxy(__spreadValues$O(__spreadValues$O({}, _TextStyle.defaultDropShadow), value)); + } else { + this._dropShadow = value ? this._createProxy(__spreadValues$O({}, _TextStyle.defaultDropShadow)) : null; + } + this.update(); + } + /** The font family, can be a single font name, or a list of names where the first is the preferred font. */ + get fontFamily() { + return this._fontFamily; + } + set fontFamily(value) { + this._fontFamily = value; + this.update(); + } + /** The font size (as a number it converts to px, but as a string, equivalents are '26px','20pt','160%' or '1.6em') */ + get fontSize() { + return this._fontSize; + } + set fontSize(value) { + if (typeof value === "string") { + this._fontSize = parseInt(value, 10); + } else { + this._fontSize = value; + } + this.update(); + } + /** + * The font style. + * @member {'normal'|'italic'|'oblique'} + */ + get fontStyle() { + return this._fontStyle; + } + set fontStyle(value) { + this._fontStyle = value; + this.update(); + } + /** + * The font variant. + * @member {'normal'|'small-caps'} + */ + get fontVariant() { + return this._fontVariant; + } + set fontVariant(value) { + this._fontVariant = value; + this.update(); + } + /** + * The font weight. + * @member {'normal'|'bold'|'bolder'|'lighter'|'100'|'200'|'300'|'400'|'500'|'600'|'700'|'800'|'900'} + */ + get fontWeight() { + return this._fontWeight; + } + set fontWeight(value) { + this._fontWeight = value; + this.update(); + } + /** The space between lines. */ + get leading() { + return this._leading; + } + set leading(value) { + this._leading = value; + this.update(); + } + /** The amount of spacing between letters, default is 0. */ + get letterSpacing() { + return this._letterSpacing; + } + set letterSpacing(value) { + this._letterSpacing = value; + this.update(); + } + /** The line height, a number that represents the vertical space that a letter uses. */ + get lineHeight() { + return this._lineHeight; + } + set lineHeight(value) { + this._lineHeight = value; + this.update(); + } + /** + * Occasionally some fonts are cropped. Adding some padding will prevent this from happening + * by adding padding to all sides of the text. + */ + get padding() { + return this._padding; + } + set padding(value) { + this._padding = value; + this.update(); + } + /** Trim transparent borders. This is an expensive operation so only use this if you have to! */ + get trim() { + return this._trim; + } + set trim(value) { + this._trim = value; + this.update(); + } + /** + * The baseline of the text that is rendered. + * @member {'alphabetic'|'top'|'hanging'|'middle'|'ideographic'|'bottom'} + */ + get textBaseline() { + return this._textBaseline; + } + set textBaseline(value) { + this._textBaseline = value; + this.update(); + } + /** + * How newlines and spaces should be handled. + * Default is 'pre' (preserve, preserve). + * + * value | New lines | Spaces + * --- | --- | --- + * 'normal' | Collapse | Collapse + * 'pre' | Preserve | Preserve + * 'pre-line' | Preserve | Collapse + * @member {'normal'|'pre'|'pre-line'} + */ + get whiteSpace() { + return this._whiteSpace; + } + set whiteSpace(value) { + this._whiteSpace = value; + this.update(); + } + /** Indicates if word wrap should be used. */ + get wordWrap() { + return this._wordWrap; + } + set wordWrap(value) { + this._wordWrap = value; + this.update(); + } + /** The width at which text will wrap, it needs wordWrap to be set to true. */ + get wordWrapWidth() { + return this._wordWrapWidth; + } + set wordWrapWidth(value) { + this._wordWrapWidth = value; + this.update(); + } + /** A fillstyle that will be used on the text e.g., 'red', '#00FF00'. */ + get fill() { + return this._originalFill; + } + set fill(value) { + if (value === this._originalFill) + return; + this._originalFill = value; + if (this._isFillStyle(value)) { + this._originalFill = this._createProxy(__spreadValues$O(__spreadValues$O({}, GraphicsContext.defaultFillStyle), value), () => { + this._fill = toFillStyle( + __spreadValues$O({}, this._originalFill), + GraphicsContext.defaultFillStyle + ); + }); + } + this._fill = toFillStyle( + value === 0 ? "black" : value, + GraphicsContext.defaultFillStyle + ); + this.update(); + } + /** A fillstyle that will be used on the text stroke, e.g., 'blue', '#FCFF00'. */ + get stroke() { + return this._originalStroke; + } + set stroke(value) { + if (value === this._originalStroke) + return; + this._originalStroke = value; + if (this._isFillStyle(value)) { + this._originalStroke = this._createProxy(__spreadValues$O(__spreadValues$O({}, GraphicsContext.defaultStrokeStyle), value), () => { + this._stroke = toStrokeStyle( + __spreadValues$O({}, this._originalStroke), + GraphicsContext.defaultStrokeStyle + ); + }); + } + this._stroke = toStrokeStyle(value, GraphicsContext.defaultStrokeStyle); + this.update(); + } + _generateKey() { + this._styleKey = generateTextStyleKey(this); + return this._styleKey; + } + update() { + this._styleKey = null; + this.emit("update", this); + } + /** Resets all properties to the default values */ + reset() { + const defaultStyle = _TextStyle.defaultTextStyle; + for (const key in defaultStyle) { + this[key] = defaultStyle[key]; + } + } + get styleKey() { + return this._styleKey || this._generateKey(); + } + /** + * Creates a new TextStyle object with the same values as this one. + * @returns New cloned TextStyle object + */ + clone() { + return new _TextStyle({ + align: this.align, + breakWords: this.breakWords, + dropShadow: this._dropShadow ? __spreadValues$O({}, this._dropShadow) : null, + fill: this._fill, + fontFamily: this.fontFamily, + fontSize: this.fontSize, + fontStyle: this.fontStyle, + fontVariant: this.fontVariant, + fontWeight: this.fontWeight, + leading: this.leading, + letterSpacing: this.letterSpacing, + lineHeight: this.lineHeight, + padding: this.padding, + stroke: this._stroke, + textBaseline: this.textBaseline, + whiteSpace: this.whiteSpace, + wordWrap: this.wordWrap, + wordWrapWidth: this.wordWrapWidth + }); + } + /** + * Destroys this text style. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the texture of the this style + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the this style + */ + destroy(options = false) { + var _a, _b, _c, _d; + this.removeAllListeners(); + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + if ((_a = this._fill) == null ? void 0 : _a.texture) { + this._fill.texture.destroy(destroyTextureSource); + } + if ((_b = this._originalFill) == null ? void 0 : _b.texture) { + this._originalFill.texture.destroy(destroyTextureSource); + } + if ((_c = this._stroke) == null ? void 0 : _c.texture) { + this._stroke.texture.destroy(destroyTextureSource); + } + if ((_d = this._originalStroke) == null ? void 0 : _d.texture) { + this._originalStroke.texture.destroy(destroyTextureSource); + } + } + this._fill = null; + this._stroke = null; + this.dropShadow = null; + this._originalStroke = null; + this._originalFill = null; + } + _createProxy(value, cb) { + return new Proxy(value, { + set: (target, property, newValue) => { + target[property] = newValue; + cb == null ? void 0 : cb(property, newValue); + this.update(); + return true; + } + }); + } + _isFillStyle(value) { + return (value != null ? value : null) !== null && !(Color.isColorLike(value) || value instanceof FillGradient || value instanceof FillPattern); + } + }; + /** The default drop shadow settings */ + _TextStyle.defaultDropShadow = { + /** Set alpha for the drop shadow */ + alpha: 1, + /** Set a angle of the drop shadow */ + angle: Math.PI / 6, + /** Set a shadow blur radius */ + blur: 0, + /** A fill style to be used on the e.g., 'red', '#00FF00' */ + color: "black", + /** Set a distance of the drop shadow */ + distance: 5 + }; + /** The default text style settings */ + _TextStyle.defaultTextStyle = { + /** + * See {@link TextStyle.align} + * @type {'left'|'center'|'right'|'justify'} + */ + align: "left", + /** See {@link TextStyle.breakWords} */ + breakWords: false, + /** See {@link TextStyle.dropShadow} */ + dropShadow: null, + /** + * See {@link TextStyle.fill} + * @type {string|string[]|number|number[]|CanvasGradient|CanvasPattern} + */ + fill: "black", + /** + * See {@link TextStyle.fontFamily} + * @type {string|string[]} + */ + fontFamily: "Arial", + /** + * See {@link TextStyle.fontSize} + * @type {number|string} + */ + fontSize: 26, + /** + * See {@link TextStyle.fontStyle} + * @type {'normal'|'italic'|'oblique'} + */ + fontStyle: "normal", + /** + * See {@link TextStyle.fontVariant} + * @type {'normal'|'small-caps'} + */ + fontVariant: "normal", + /** + * See {@link TextStyle.fontWeight} + * @type {'normal'|'bold'|'bolder'|'lighter'|'100'|'200'|'300'|'400'|'500'|'600'|'700'|'800'|'900'} + */ + fontWeight: "normal", + /** See {@link TextStyle.leading} */ + leading: 0, + /** See {@link TextStyle.letterSpacing} */ + letterSpacing: 0, + /** See {@link TextStyle.lineHeight} */ + lineHeight: 0, + /** See {@link TextStyle.padding} */ + padding: 0, + /** + * See {@link TextStyle.stroke} + * @type {string|number} + */ + stroke: null, + /** + * See {@link TextStyle.textBaseline} + * @type {'alphabetic'|'top'|'hanging'|'middle'|'ideographic'|'bottom'} + */ + textBaseline: "alphabetic", + /** See {@link TextStyle.trim} */ + trim: false, + /** + * See {@link TextStyle.whiteSpace} + * @type {'normal'|'pre'|'pre-line'} + */ + whiteSpace: "pre", + /** See {@link TextStyle.wordWrap} */ + wordWrap: false, + /** See {@link TextStyle.wordWrapWidth} */ + wordWrapWidth: 100 + }; + let TextStyle = _TextStyle; + function convertV7Tov8Style(style) { + var _a, _b, _c, _d, _e; + const oldStyle = style; + if (typeof oldStyle.dropShadow === "boolean" && oldStyle.dropShadow) { + const defaults = TextStyle.defaultDropShadow; + style.dropShadow = { + alpha: (_a = oldStyle.dropShadowAlpha) != null ? _a : defaults.alpha, + angle: (_b = oldStyle.dropShadowAngle) != null ? _b : defaults.angle, + blur: (_c = oldStyle.dropShadowBlur) != null ? _c : defaults.blur, + color: (_d = oldStyle.dropShadowColor) != null ? _d : defaults.color, + distance: (_e = oldStyle.dropShadowDistance) != null ? _e : defaults.distance + }; + } + if (oldStyle.strokeThickness !== void 0) { + deprecation(v8_0_0, "strokeThickness is now a part of stroke"); + const color = oldStyle.stroke; + let obj = {}; + if (Color.isColorLike(color)) { + obj.color = color; + } else if (color instanceof FillGradient || color instanceof FillPattern) { + obj.fill = color; + } else if (Object.hasOwnProperty.call(color, "color") || Object.hasOwnProperty.call(color, "fill")) { + obj = color; + } else { + throw new Error("Invalid stroke value."); + } + style.stroke = __spreadProps$j(__spreadValues$O({}, obj), { + width: oldStyle.strokeThickness + }); + } + if (Array.isArray(oldStyle.fillGradientStops)) { + deprecation(v8_0_0, "gradient fill is now a fill pattern: `new FillGradient(...)`"); + let fontSize; + if (style.fontSize == null) { + style.fontSize = TextStyle.defaultTextStyle.fontSize; + } else if (typeof style.fontSize === "string") { + fontSize = parseInt(style.fontSize, 10); + } else { + fontSize = style.fontSize; + } + const gradientFill = new FillGradient(0, 0, 0, fontSize * 1.7); + const fills = oldStyle.fillGradientStops.map((color) => Color.shared.setValue(color).toNumber()); + fills.forEach((number, index) => { + const ratio = index / (fills.length - 1); + gradientFill.addColorStop(ratio, number); + }); + style.fill = { + fill: gradientFill + }; + } + } + + "use strict"; + const tempBounds$3 = new Bounds(); + function getPo2TextureFromSource(image, width, height, resolution) { + const bounds = tempBounds$3; + bounds.minX = 0; + bounds.minY = 0; + bounds.maxX = image.width / resolution | 0; + bounds.maxY = image.height / resolution | 0; + const texture = TexturePool.getOptimalTexture( + bounds.width, + bounds.height, + resolution, + false + ); + texture.source.uploadMethodId = "image"; + texture.source.resource = image; + texture.source.alphaMode = "premultiply-alpha-on-upload"; + texture.frame.width = width / resolution; + texture.frame.height = height / resolution; + texture.source.emit("update", texture.source); + texture.updateUvs(); + return texture; + } + + "use strict"; + const genericFontFamilies = [ + "serif", + "sans-serif", + "monospace", + "cursive", + "fantasy", + "system-ui" + ]; + function fontStringFromTextStyle(style) { + const fontSizeString = typeof style.fontSize === "number" ? `${style.fontSize}px` : style.fontSize; + let fontFamilies = style.fontFamily; + if (!Array.isArray(style.fontFamily)) { + fontFamilies = style.fontFamily.split(","); + } + for (let i = fontFamilies.length - 1; i >= 0; i--) { + let fontFamily = fontFamilies[i].trim(); + if (!/([\"\'])[^\'\"]+\1/.test(fontFamily) && !genericFontFamilies.includes(fontFamily)) { + fontFamily = `"${fontFamily}"`; + } + fontFamilies[i] = fontFamily; + } + return `${style.fontStyle} ${style.fontVariant} ${style.fontWeight} ${fontSizeString} ${fontFamilies.join(",")}`; + } + + "use strict"; + const contextSettings = { + // TextMetrics requires getImageData readback for measuring fonts. + willReadFrequently: true + }; + const _CanvasTextMetrics = class _CanvasTextMetrics { + /** + * Checking that we can use modern canvas 2D API. + * + * Note: This is an unstable API, Chrome < 94 use `textLetterSpacing`, later versions use `letterSpacing`. + * @see TextMetrics.experimentalLetterSpacing + * @see https://developer.mozilla.org/en-US/docs/Web/API/ICanvasRenderingContext2D/letterSpacing + * @see https://developer.chrome.com/origintrials/#/view_trial/3585991203293757441 + */ + static get experimentalLetterSpacingSupported() { + let result = _CanvasTextMetrics._experimentalLetterSpacingSupported; + if (result !== void 0) { + const proto = DOMAdapter.get().getCanvasRenderingContext2D().prototype; + result = _CanvasTextMetrics._experimentalLetterSpacingSupported = "letterSpacing" in proto || "textLetterSpacing" in proto; + } + return result; + } + /** + * @param text - the text that was measured + * @param style - the style that was measured + * @param width - the measured width of the text + * @param height - the measured height of the text + * @param lines - an array of the lines of text broken by new lines and wrapping if specified in style + * @param lineWidths - an array of the line widths for each line matched to `lines` + * @param lineHeight - the measured line height for this style + * @param maxLineWidth - the maximum line width for all measured lines + * @param {FontMetrics} fontProperties - the font properties object from TextMetrics.measureFont + */ + constructor(text, style, width, height, lines, lineWidths, lineHeight, maxLineWidth, fontProperties) { + this.text = text; + this.style = style; + this.width = width; + this.height = height; + this.lines = lines; + this.lineWidths = lineWidths; + this.lineHeight = lineHeight; + this.maxLineWidth = maxLineWidth; + this.fontProperties = fontProperties; + } + /** + * Measures the supplied string of text and returns a Rectangle. + * @param text - The text to measure. + * @param style - The text style to use for measuring + * @param canvas - optional specification of the canvas to use for measuring. + * @param wordWrap + * @returns Measured width and height of the text. + */ + static measureText(text = " ", style, canvas = _CanvasTextMetrics._canvas, wordWrap = style.wordWrap) { + var _a; + const textKey = `${text}:${style.styleKey}`; + if (_CanvasTextMetrics._measurementCache[textKey]) + return _CanvasTextMetrics._measurementCache[textKey]; + const font = fontStringFromTextStyle(style); + const fontProperties = _CanvasTextMetrics.measureFont(font); + if (fontProperties.fontSize === 0) { + fontProperties.fontSize = style.fontSize; + fontProperties.ascent = style.fontSize; + } + const context = _CanvasTextMetrics.__context; + context.font = font; + const outputText = wordWrap ? _CanvasTextMetrics._wordWrap(text, style, canvas) : text; + const lines = outputText.split(/(?:\r\n|\r|\n)/); + const lineWidths = new Array(lines.length); + let maxLineWidth = 0; + for (let i = 0; i < lines.length; i++) { + const lineWidth = _CanvasTextMetrics._measureText(lines[i], style.letterSpacing, context); + lineWidths[i] = lineWidth; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + } + const strokeWidth = ((_a = style._stroke) == null ? void 0 : _a.width) || 0; + let width = maxLineWidth + strokeWidth; + if (style.dropShadow) { + width += style.dropShadow.distance; + } + const lineHeight = style.lineHeight || fontProperties.fontSize + strokeWidth; + let height = Math.max(lineHeight, fontProperties.fontSize + strokeWidth * 2) + (lines.length - 1) * (lineHeight + style.leading); + if (style.dropShadow) { + height += style.dropShadow.distance; + } + const measurements = new _CanvasTextMetrics( + text, + style, + width, + height, + lines, + lineWidths, + lineHeight + style.leading, + maxLineWidth, + fontProperties + ); + return measurements; + } + static _measureText(text, letterSpacing, context) { + let useExperimentalLetterSpacing = false; + if (_CanvasTextMetrics.experimentalLetterSpacingSupported) { + if (_CanvasTextMetrics.experimentalLetterSpacing) { + context.letterSpacing = `${letterSpacing}px`; + context.textLetterSpacing = `${letterSpacing}px`; + useExperimentalLetterSpacing = true; + } else { + context.letterSpacing = "0px"; + context.textLetterSpacing = "0px"; + } + } + let width = context.measureText(text).width; + if (width > 0) { + if (useExperimentalLetterSpacing) { + width -= letterSpacing; + } else { + width += (_CanvasTextMetrics.graphemeSegmenter(text).length - 1) * letterSpacing; + } + } + return width; + } + /** + * Applies newlines to a string to have it optimally fit into the horizontal + * bounds set by the Text object's wordWrapWidth property. + * @param text - String to apply word wrapping to + * @param style - the style to use when wrapping + * @param canvas - optional specification of the canvas to use for measuring. + * @returns New string with new lines applied where required + */ + static _wordWrap(text, style, canvas = _CanvasTextMetrics._canvas) { + const context = canvas.getContext("2d", contextSettings); + let width = 0; + let line = ""; + let lines = ""; + const cache = /* @__PURE__ */ Object.create(null); + const { letterSpacing, whiteSpace } = style; + const collapseSpaces = _CanvasTextMetrics._collapseSpaces(whiteSpace); + const collapseNewlines = _CanvasTextMetrics._collapseNewlines(whiteSpace); + let canPrependSpaces = !collapseSpaces; + const wordWrapWidth = style.wordWrapWidth + letterSpacing; + const tokens = _CanvasTextMetrics._tokenize(text); + for (let i = 0; i < tokens.length; i++) { + let token = tokens[i]; + if (_CanvasTextMetrics._isNewline(token)) { + if (!collapseNewlines) { + lines += _CanvasTextMetrics._addLine(line); + canPrependSpaces = !collapseSpaces; + line = ""; + width = 0; + continue; + } + token = " "; + } + if (collapseSpaces) { + const currIsBreakingSpace = _CanvasTextMetrics.isBreakingSpace(token); + const lastIsBreakingSpace = _CanvasTextMetrics.isBreakingSpace(line[line.length - 1]); + if (currIsBreakingSpace && lastIsBreakingSpace) { + continue; + } + } + const tokenWidth = _CanvasTextMetrics._getFromCache(token, letterSpacing, cache, context); + if (tokenWidth > wordWrapWidth) { + if (line !== "") { + lines += _CanvasTextMetrics._addLine(line); + line = ""; + width = 0; + } + if (_CanvasTextMetrics.canBreakWords(token, style.breakWords)) { + const characters = _CanvasTextMetrics.wordWrapSplit(token); + for (let j = 0; j < characters.length; j++) { + let char = characters[j]; + let lastChar = char; + let k = 1; + while (characters[j + k]) { + const nextChar = characters[j + k]; + if (!_CanvasTextMetrics.canBreakChars(lastChar, nextChar, token, j, style.breakWords)) { + char += nextChar; + } else { + break; + } + lastChar = nextChar; + k++; + } + j += k - 1; + const characterWidth = _CanvasTextMetrics._getFromCache(char, letterSpacing, cache, context); + if (characterWidth + width > wordWrapWidth) { + lines += _CanvasTextMetrics._addLine(line); + canPrependSpaces = false; + line = ""; + width = 0; + } + line += char; + width += characterWidth; + } + } else { + if (line.length > 0) { + lines += _CanvasTextMetrics._addLine(line); + line = ""; + width = 0; + } + const isLastToken = i === tokens.length - 1; + lines += _CanvasTextMetrics._addLine(token, !isLastToken); + canPrependSpaces = false; + line = ""; + width = 0; + } + } else { + if (tokenWidth + width > wordWrapWidth) { + canPrependSpaces = false; + lines += _CanvasTextMetrics._addLine(line); + line = ""; + width = 0; + } + if (line.length > 0 || !_CanvasTextMetrics.isBreakingSpace(token) || canPrependSpaces) { + line += token; + width += tokenWidth; + } + } + } + lines += _CanvasTextMetrics._addLine(line, false); + return lines; + } + /** + * Convienience function for logging each line added during the wordWrap method. + * @param line - The line of text to add + * @param newLine - Add new line character to end + * @returns A formatted line + */ + static _addLine(line, newLine = true) { + line = _CanvasTextMetrics._trimRight(line); + line = newLine ? `${line} +` : line; + return line; + } + /** + * Gets & sets the widths of calculated characters in a cache object + * @param key - The key + * @param letterSpacing - The letter spacing + * @param cache - The cache + * @param context - The canvas context + * @returns The from cache. + */ + static _getFromCache(key, letterSpacing, cache, context) { + let width = cache[key]; + if (typeof width !== "number") { + width = _CanvasTextMetrics._measureText(key, letterSpacing, context) + letterSpacing; + cache[key] = width; + } + return width; + } + /** + * Determines whether we should collapse breaking spaces. + * @param whiteSpace - The TextStyle property whiteSpace + * @returns Should collapse + */ + static _collapseSpaces(whiteSpace) { + return whiteSpace === "normal" || whiteSpace === "pre-line"; + } + /** + * Determines whether we should collapse newLine chars. + * @param whiteSpace - The white space + * @returns should collapse + */ + static _collapseNewlines(whiteSpace) { + return whiteSpace === "normal"; + } + /** + * Trims breaking whitespaces from string. + * @param text - The text + * @returns Trimmed string + */ + static _trimRight(text) { + if (typeof text !== "string") { + return ""; + } + for (let i = text.length - 1; i >= 0; i--) { + const char = text[i]; + if (!_CanvasTextMetrics.isBreakingSpace(char)) { + break; + } + text = text.slice(0, -1); + } + return text; + } + /** + * Determines if char is a newline. + * @param char - The character + * @returns True if newline, False otherwise. + */ + static _isNewline(char) { + if (typeof char !== "string") { + return false; + } + return _CanvasTextMetrics._newlines.includes(char.charCodeAt(0)); + } + /** + * Determines if char is a breaking whitespace. + * + * It allows one to determine whether char should be a breaking whitespace + * For example certain characters in CJK langs or numbers. + * It must return a boolean. + * @param char - The character + * @param [_nextChar] - The next character + * @returns True if whitespace, False otherwise. + */ + static isBreakingSpace(char, _nextChar) { + if (typeof char !== "string") { + return false; + } + return _CanvasTextMetrics._breakingSpaces.includes(char.charCodeAt(0)); + } + /** + * Splits a string into words, breaking-spaces and newLine characters + * @param text - The text + * @returns A tokenized array + */ + static _tokenize(text) { + const tokens = []; + let token = ""; + if (typeof text !== "string") { + return tokens; + } + for (let i = 0; i < text.length; i++) { + const char = text[i]; + const nextChar = text[i + 1]; + if (_CanvasTextMetrics.isBreakingSpace(char, nextChar) || _CanvasTextMetrics._isNewline(char)) { + if (token !== "") { + tokens.push(token); + token = ""; + } + tokens.push(char); + continue; + } + token += char; + } + if (token !== "") { + tokens.push(token); + } + return tokens; + } + /** + * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior. + * + * It allows one to customise which words should break + * Examples are if the token is CJK or numbers. + * It must return a boolean. + * @param _token - The token + * @param breakWords - The style attr break words + * @returns Whether to break word or not + */ + static canBreakWords(_token, breakWords) { + return breakWords; + } + /** + * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior. + * + * It allows one to determine whether a pair of characters + * should be broken by newlines + * For example certain characters in CJK langs or numbers. + * It must return a boolean. + * @param _char - The character + * @param _nextChar - The next character + * @param _token - The token/word the characters are from + * @param _index - The index in the token of the char + * @param _breakWords - The style attr break words + * @returns whether to break word or not + */ + static canBreakChars(_char, _nextChar, _token, _index, _breakWords) { + return true; + } + /** + * Overridable helper method used internally by TextMetrics, exposed to allow customizing the class's behavior. + * + * It is called when a token (usually a word) has to be split into separate pieces + * in order to determine the point to break a word. + * It must return an array of characters. + * @param token - The token to split + * @returns The characters of the token + * @see CanvasTextMetrics.graphemeSegmenter + */ + static wordWrapSplit(token) { + return _CanvasTextMetrics.graphemeSegmenter(token); + } + /** + * Calculates the ascent, descent and fontSize of a given font-style + * @param font - String representing the style of the font + * @returns Font properties object + */ + static measureFont(font) { + if (_CanvasTextMetrics._fonts[font]) { + return _CanvasTextMetrics._fonts[font]; + } + const context = _CanvasTextMetrics._context; + context.font = font; + const metrics = context.measureText(_CanvasTextMetrics.METRICS_STRING + _CanvasTextMetrics.BASELINE_SYMBOL); + const properties = { + ascent: metrics.actualBoundingBoxAscent, + descent: metrics.actualBoundingBoxDescent, + fontSize: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + }; + _CanvasTextMetrics._fonts[font] = properties; + return properties; + } + /** + * Clear font metrics in metrics cache. + * @param {string} [font] - font name. If font name not set then clear cache for all fonts. + */ + static clearMetrics(font = "") { + if (font) { + delete _CanvasTextMetrics._fonts[font]; + } else { + _CanvasTextMetrics._fonts = {}; + } + } + /** + * Cached canvas element for measuring text + * TODO: this should be private, but isn't because of backward compat, will fix later. + * @ignore + */ + static get _canvas() { + if (!_CanvasTextMetrics.__canvas) { + let canvas; + try { + const c = new OffscreenCanvas(0, 0); + const context = c.getContext("2d", contextSettings); + if (context == null ? void 0 : context.measureText) { + _CanvasTextMetrics.__canvas = c; + return c; + } + canvas = DOMAdapter.get().createCanvas(); + } catch (ex) { + canvas = DOMAdapter.get().createCanvas(); + } + canvas.width = canvas.height = 10; + _CanvasTextMetrics.__canvas = canvas; + } + return _CanvasTextMetrics.__canvas; + } + /** + * TODO: this should be private, but isn't because of backward compat, will fix later. + * @ignore + */ + static get _context() { + if (!_CanvasTextMetrics.__context) { + _CanvasTextMetrics.__context = _CanvasTextMetrics._canvas.getContext("2d", contextSettings); + } + return _CanvasTextMetrics.__context; + } + }; + /** + * String used for calculate font metrics. + * These characters are all tall to help calculate the height required for text. + */ + _CanvasTextMetrics.METRICS_STRING = "|\xC9q\xC5"; + /** Baseline symbol for calculate font metrics. */ + _CanvasTextMetrics.BASELINE_SYMBOL = "M"; + /** Baseline multiplier for calculate font metrics. */ + _CanvasTextMetrics.BASELINE_MULTIPLIER = 1.4; + /** Height multiplier for setting height of canvas to calculate font metrics. */ + _CanvasTextMetrics.HEIGHT_MULTIPLIER = 2; + /** + * A Unicode "character", or "grapheme cluster", can be composed of multiple Unicode code points, + * such as letters with diacritical marks (e.g. `'\u0065\u0301'`, letter e with acute) + * or emojis with modifiers (e.g. `'\uD83E\uDDD1\u200D\uD83D\uDCBB'`, technologist). + * The new `Intl.Segmenter` API in ES2022 can split the string into grapheme clusters correctly. If it is not available, + * PixiJS will fallback to use the iterator of String, which can only spilt the string into code points. + * If you want to get full functionality in environments that don't support `Intl.Segmenter` (such as Firefox), + * you can use other libraries such as [grapheme-splitter]{@link https://www.npmjs.com/package/grapheme-splitter} + * or [graphemer]{@link https://www.npmjs.com/package/graphemer} to create a polyfill. Since these libraries can be + * relatively large in size to handle various Unicode grapheme clusters properly, PixiJS won't use them directly. + */ + _CanvasTextMetrics.graphemeSegmenter = (() => { + if (typeof (Intl == null ? void 0 : Intl.Segmenter) === "function") { + const segmenter = new Intl.Segmenter(); + return (s) => [...segmenter.segment(s)].map((x) => x.segment); + } + return (s) => [...s]; + })(); + /** + * New rendering behavior for letter-spacing which uses Chrome's new native API. This will + * lead to more accurate letter-spacing results because it does not try to manually draw + * each character. However, this Chrome API is experimental and may not serve all cases yet. + * @see TextMetrics.experimentalLetterSpacingSupported + */ + _CanvasTextMetrics.experimentalLetterSpacing = false; + /** Cache of {@see TextMetrics.FontMetrics} objects. */ + _CanvasTextMetrics._fonts = {}; + /** Cache of new line chars. */ + _CanvasTextMetrics._newlines = [ + 10, + // line feed + 13 + // carriage return + ]; + /** Cache of breaking spaces. */ + _CanvasTextMetrics._breakingSpaces = [ + 9, + // character tabulation + 32, + // space + 8192, + // en quad + 8193, + // em quad + 8194, + // en space + 8195, + // em space + 8196, + // three-per-em space + 8197, + // four-per-em space + 8198, + // six-per-em space + 8200, + // punctuation space + 8201, + // thin space + 8202, + // hair space + 8287, + // medium mathematical space + 12288 + // ideographic space + ]; + _CanvasTextMetrics._measurementCache = {}; + let CanvasTextMetrics = _CanvasTextMetrics; + + "use strict"; + function getCanvasFillStyle(fillStyle, context) { + if (fillStyle.texture === Texture.WHITE && !fillStyle.fill) { + return Color.shared.setValue(fillStyle.color).toHex(); + } else if (!fillStyle.fill) { + const pattern = context.createPattern(fillStyle.texture.source.resource, "repeat"); + const tempMatrix = fillStyle.matrix.copyTo(Matrix.shared); + tempMatrix.scale(fillStyle.texture.frame.width, fillStyle.texture.frame.height); + pattern.setTransform(tempMatrix); + return pattern; + } else if (fillStyle.fill instanceof FillPattern) { + const fillPattern = fillStyle.fill; + const pattern = context.createPattern(fillPattern.texture.source.resource, "repeat"); + const tempMatrix = fillPattern.transform.copyTo(Matrix.shared); + tempMatrix.scale( + fillPattern.texture.frame.width, + fillPattern.texture.frame.height + ); + pattern.setTransform(tempMatrix); + return pattern; + } else if (fillStyle.fill instanceof FillGradient) { + const fillGradient = fillStyle.fill; + if (fillGradient.type === "linear") { + const gradient = context.createLinearGradient( + fillGradient.x0, + fillGradient.y0, + fillGradient.x1, + fillGradient.y1 + ); + fillGradient.gradientStops.forEach((stop) => { + gradient.addColorStop(stop.offset, Color.shared.setValue(stop.color).toHex()); + }); + return gradient; + } + } + warn("FillStyle not recognised", fillStyle); + return "red"; + } + + "use strict"; + class CanvasTextSystem { + constructor(_renderer) { + this._activeTextures = {}; + this._renderer = _renderer; + } + getTextureSize(text, resolution, style) { + const measured = CanvasTextMetrics.measureText(text || " ", style); + let width = Math.ceil(Math.ceil(Math.max(1, measured.width) + style.padding * 2) * resolution); + let height = Math.ceil(Math.ceil(Math.max(1, measured.height) + style.padding * 2) * resolution); + width = Math.ceil(width - 1e-6); + height = Math.ceil(height - 1e-6); + width = nextPow2(width); + height = nextPow2(height); + return { width, height }; + } + getTexture(options, resolution, style, _textKey) { + if (typeof options === "string") { + deprecation("8.0.0", "CanvasTextSystem.getTexture: Use object TextOptions instead of separate arguments"); + options = { + text: options, + style, + resolution + }; + } + if (!(options.style instanceof TextStyle)) { + options.style = new TextStyle(options.style); + } + const { texture, canvasAndContext } = this.createTextureAndCanvas( + options + ); + this._renderer.texture.initSource(texture._source); + CanvasPool.returnCanvasAndContext(canvasAndContext); + return texture; + } + createTextureAndCanvas(options) { + var _a; + const { text, style } = options; + const resolution = (_a = options.resolution) != null ? _a : this._renderer.resolution; + const measured = CanvasTextMetrics.measureText(text || " ", style); + const width = Math.ceil(Math.ceil(Math.max(1, measured.width) + style.padding * 2) * resolution); + const height = Math.ceil(Math.ceil(Math.max(1, measured.height) + style.padding * 2) * resolution); + const canvasAndContext = CanvasPool.getOptimalCanvasAndContext(width, height); + const { canvas } = canvasAndContext; + this.renderTextToCanvas(text, style, resolution, canvasAndContext); + const texture = getPo2TextureFromSource(canvas, width, height, resolution); + if (style.trim) { + const trimmed = getCanvasBoundingBox(canvas, resolution); + texture.frame.copyFrom(trimmed); + texture.updateUvs(); + } + return { texture, canvasAndContext }; + } + getManagedTexture(text) { + const textKey = text._getKey(); + if (this._activeTextures[textKey]) { + this._increaseReferenceCount(textKey); + return this._activeTextures[textKey].texture; + } + const { texture, canvasAndContext } = this.createTextureAndCanvas(text); + this._activeTextures[textKey] = { + canvasAndContext, + texture, + usageCount: 1 + }; + return texture; + } + _increaseReferenceCount(textKey) { + this._activeTextures[textKey].usageCount++; + } + decreaseReferenceCount(textKey) { + const activeTexture = this._activeTextures[textKey]; + activeTexture.usageCount--; + if (activeTexture.usageCount === 0) { + CanvasPool.returnCanvasAndContext(activeTexture.canvasAndContext); + TexturePool.returnTexture(activeTexture.texture); + const source = activeTexture.texture.source; + source.resource = null; + source.uploadMethodId = "unknown"; + source.alphaMode = "no-premultiply-alpha"; + this._activeTextures[textKey] = null; + } + } + getReferenceCount(textKey) { + return this._activeTextures[textKey].usageCount; + } + /** + * Renders text to its canvas, and updates its texture. + * + * By default this is used internally to ensure the texture is correct before rendering, + * but it can be used called externally, for example from this class to 'pre-generate' the texture from a piece of text, + * and then shared across multiple Sprites. + * @param text + * @param style + * @param resolution + * @param canvasAndContext + */ + renderTextToCanvas(text, style, resolution, canvasAndContext) { + var _a, _b, _c, _d, _e, _f, _g; + const { canvas, context } = canvasAndContext; + const font = fontStringFromTextStyle(style); + const measured = CanvasTextMetrics.measureText(text || " ", style); + const lines = measured.lines; + const lineHeight = measured.lineHeight; + const lineWidths = measured.lineWidths; + const maxLineWidth = measured.maxLineWidth; + const fontProperties = measured.fontProperties; + const height = canvas.height; + context.resetTransform(); + context.scale(resolution, resolution); + const padding = style.padding * 2; + context.clearRect(0, 0, measured.width + 4 + padding, measured.height + 4 + padding); + if ((_a = style._stroke) == null ? void 0 : _a.width) { + const strokeStyle = style._stroke; + context.lineWidth = strokeStyle.width; + context.miterLimit = strokeStyle.miterLimit; + context.lineJoin = strokeStyle.join; + context.lineCap = strokeStyle.cap; + } + context.font = font; + let linePositionX; + let linePositionY; + const passesCount = style.dropShadow ? 2 : 1; + for (let i = 0; i < passesCount; ++i) { + const isShadowPass = style.dropShadow && i === 0; + const dsOffsetText = isShadowPass ? Math.ceil(Math.max(1, height) + style.padding * 2) : 0; + const dsOffsetShadow = dsOffsetText * resolution; + if (isShadowPass) { + context.fillStyle = "black"; + context.strokeStyle = "black"; + const shadowOptions = style.dropShadow; + const dropShadowColor = shadowOptions.color; + const dropShadowAlpha = shadowOptions.alpha; + context.shadowColor = Color.shared.setValue(dropShadowColor).setAlpha(dropShadowAlpha).toRgbaString(); + const dropShadowBlur = shadowOptions.blur * resolution; + const dropShadowDistance = shadowOptions.distance * resolution; + context.shadowBlur = dropShadowBlur; + context.shadowOffsetX = Math.cos(shadowOptions.angle) * dropShadowDistance; + context.shadowOffsetY = Math.sin(shadowOptions.angle) * dropShadowDistance + dsOffsetShadow; + } else { + context.globalAlpha = (_c = (_b = style._fill) == null ? void 0 : _b.alpha) != null ? _c : 1; + context.fillStyle = style._fill ? getCanvasFillStyle(style._fill, context) : null; + if ((_d = style._stroke) == null ? void 0 : _d.width) { + context.strokeStyle = getCanvasFillStyle(style._stroke, context); + } + context.shadowColor = "black"; + } + let linePositionYShift = (lineHeight - fontProperties.fontSize) / 2; + if (lineHeight - fontProperties.fontSize < 0) { + linePositionYShift = 0; + } + const strokeWidth = (_f = (_e = style._stroke) == null ? void 0 : _e.width) != null ? _f : 0; + for (let i2 = 0; i2 < lines.length; i2++) { + linePositionX = strokeWidth / 2; + linePositionY = strokeWidth / 2 + i2 * lineHeight + fontProperties.ascent + linePositionYShift; + if (style.align === "right") { + linePositionX += maxLineWidth - lineWidths[i2]; + } else if (style.align === "center") { + linePositionX += (maxLineWidth - lineWidths[i2]) / 2; + } + if ((_g = style._stroke) == null ? void 0 : _g.width) { + this._drawLetterSpacing( + lines[i2], + style, + canvasAndContext, + linePositionX + style.padding, + linePositionY + style.padding - dsOffsetText, + true + ); + } + if (style._fill !== void 0) { + this._drawLetterSpacing( + lines[i2], + style, + canvasAndContext, + linePositionX + style.padding, + linePositionY + style.padding - dsOffsetText + ); + } + } + } + } + /** + * Render the text with letter-spacing. + * @param text - The text to draw + * @param style + * @param canvasAndContext + * @param x - Horizontal position to draw the text + * @param y - Vertical position to draw the text + * @param isStroke - Is this drawing for the outside stroke of the + * text? If not, it's for the inside fill + */ + _drawLetterSpacing(text, style, canvasAndContext, x, y, isStroke = false) { + const { context } = canvasAndContext; + const letterSpacing = style.letterSpacing; + let useExperimentalLetterSpacing = false; + if (CanvasTextMetrics.experimentalLetterSpacingSupported) { + if (CanvasTextMetrics.experimentalLetterSpacing) { + context.letterSpacing = `${letterSpacing}px`; + context.textLetterSpacing = `${letterSpacing}px`; + useExperimentalLetterSpacing = true; + } else { + context.letterSpacing = "0px"; + context.textLetterSpacing = "0px"; + } + } + if (letterSpacing === 0 || useExperimentalLetterSpacing) { + if (isStroke) { + context.strokeText(text, x, y); + } else { + context.fillText(text, x, y); + } + return; + } + let currentPosition = x; + const stringArray = CanvasTextMetrics.graphemeSegmenter(text); + let previousWidth = context.measureText(text).width; + let currentWidth = 0; + for (let i = 0; i < stringArray.length; ++i) { + const currentChar = stringArray[i]; + if (isStroke) { + context.strokeText(currentChar, currentPosition, y); + } else { + context.fillText(currentChar, currentPosition, y); + } + let textStr = ""; + for (let j = i + 1; j < stringArray.length; ++j) { + textStr += stringArray[j]; + } + currentWidth = context.measureText(textStr).width; + currentPosition += previousWidth - currentWidth + letterSpacing; + previousWidth = currentWidth; + } + } + destroy() { + this._activeTextures = null; + } + } + /** @ignore */ + CanvasTextSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "canvasText" + }; + + "use strict"; + extensions.add(CanvasTextSystem); + extensions.add(CanvasTextPipe); + + "use strict"; + var __defProp$N = Object.defineProperty; + var __getOwnPropSymbols$N = Object.getOwnPropertySymbols; + var __hasOwnProp$N = Object.prototype.hasOwnProperty; + var __propIsEnum$N = Object.prototype.propertyIsEnumerable; + var __defNormalProp$N = (obj, key, value) => key in obj ? __defProp$N(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$N = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$N.call(b, prop)) + __defNormalProp$N(a, prop, b[prop]); + if (__getOwnPropSymbols$N) + for (var prop of __getOwnPropSymbols$N(b)) { + if (__propIsEnum$N.call(b, prop)) + __defNormalProp$N(a, prop, b[prop]); + } + return a; + }; + var __objRest$g = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$N.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$N) + for (var prop of __getOwnPropSymbols$N(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$N.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class Graphics extends Container { + /** + * @param options - Options for the Graphics. + */ + constructor(options) { + if (options instanceof GraphicsContext) { + options = { context: options }; + } + const _a = options || {}, { context, roundPixels } = _a, rest = __objRest$g(_a, ["context", "roundPixels"]); + super(__spreadValues$N({ + label: "Graphics" + }, rest)); + this.canBundle = true; + this.renderPipeId = "graphics"; + this._roundPixels = 0; + if (!context) { + this._context = this._ownedContext = new GraphicsContext(); + } else { + this._context = context; + } + this._context.on("update", this.onViewUpdate, this); + this.allowChildren = false; + this.roundPixels = roundPixels != null ? roundPixels : false; + } + set context(context) { + if (context === this._context) + return; + this._context.off("update", this.onViewUpdate, this); + this._context = context; + this._context.on("update", this.onViewUpdate, this); + this.onViewUpdate(); + } + get context() { + return this._context; + } + /** + * The local bounds of the graphic. + * @type {rendering.Bounds} + */ + get bounds() { + return this._context.bounds; + } + /** + * Adds the bounds of this object to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + bounds.addBounds(this._context.bounds); + } + /** + * Checks if the object contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + return this._context.containsPoint(point); + } + /** + * Whether or not to round the x/y position of the graphic. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + onViewUpdate() { + this._didChangeId += 1 << 12; + this._didGraphicsUpdate = true; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + /** + * Destroys this graphics renderable and optionally its context. + * @param options - Options parameter. A boolean will act as if all options + * + * If the context was created by this graphics and `destroy(false)` or `destroy()` is called + * then the context will still be destroyed. + * + * If you want to explicitly not destroy this context that this graphics created, + * then you should pass destroy({ context: false }) + * + * If the context was passed in as an argument to the constructor then it will not be destroyed + * @param {boolean} [options.texture=false] - Should destroy the texture of the graphics context + * @param {boolean} [options.textureSource=false] - Should destroy the texture source of the graphics context + * @param {boolean} [options.context=false] - Should destroy the context + */ + destroy(options) { + if (this._ownedContext && !options) { + this._ownedContext.destroy(options); + } else if (options === true || (options == null ? void 0 : options.context) === true) { + this._context.destroy(options); + } + this._ownedContext = null; + this._context = null; + super.destroy(options); + } + _callContextMethod(method, args) { + this.context[method](...args); + return this; + } + // --------------------------------------- GraphicsContext methods --------------------------------------- + /** + * Sets the current fill style of the graphics context. The fill style can be a color, gradient, + * pattern, or a more complex style defined by a FillStyle object. + * @param {FillInput} args - The fill style to apply. This can be a simple color, a gradient or + * pattern object, or a FillStyle or ConvertedFillStyle object. + * @returns The instance of the current GraphicsContext for method chaining. + */ + setFillStyle(...args) { + return this._callContextMethod("setFillStyle", args); + } + /** + * Sets the current stroke style of the graphics context. Similar to fill styles, stroke styles can + * encompass colors, gradients, patterns, or more detailed configurations via a StrokeStyle object. + * @param {StrokeInput} args - The stroke style to apply. Can be defined as a color, a gradient or pattern, + * or a StrokeStyle or ConvertedStrokeStyle object. + * @returns The instance of the current GraphicsContext for method chaining. + */ + setStrokeStyle(...args) { + return this._callContextMethod("setStrokeStyle", args); + } + fill(...args) { + return this._callContextMethod("fill", args); + } + /** + * Strokes the current path with the current stroke style. This method can take an optional + * FillStyle parameter to define the stroke's appearance, including its color, width, and other properties. + * @param {FillStyle} args - (Optional) The stroke style to apply. Can be defined as a simple color or a more + * complex style object. If omitted, uses the current stroke style. + * @returns The instance of the current GraphicsContext for method chaining. + */ + stroke(...args) { + return this._callContextMethod("stroke", args); + } + texture(...args) { + return this._callContextMethod("texture", args); + } + /** + * Resets the current path. Any previous path and its commands are discarded and a new path is + * started. This is typically called before beginning a new shape or series of drawing commands. + * @returns The instance of the current GraphicsContext for method chaining. + */ + beginPath() { + return this._callContextMethod("beginPath", []); + } + /** + * Applies a cutout to the last drawn shape. This is used to create holes or complex shapes by + * subtracting a path from the previously drawn path. If a hole is not completely in a shape, it will + * fail to cut correctly! + */ + cut() { + return this._callContextMethod("cut", []); + } + arc(...args) { + return this._callContextMethod("arc", args); + } + arcTo(...args) { + return this._callContextMethod("arcTo", args); + } + arcToSvg(...args) { + return this._callContextMethod("arcToSvg", args); + } + bezierCurveTo(...args) { + return this._callContextMethod("bezierCurveTo", args); + } + /** + * Closes the current path by drawing a straight line back to the start. + * If the shape is already closed or there are no points in the path, this method does nothing. + * @returns The instance of the current object for chaining. + */ + closePath() { + return this._callContextMethod("closePath", []); + } + ellipse(...args) { + return this._callContextMethod("ellipse", args); + } + circle(...args) { + return this._callContextMethod("circle", args); + } + path(...args) { + return this._callContextMethod("path", args); + } + lineTo(...args) { + return this._callContextMethod("lineTo", args); + } + moveTo(...args) { + return this._callContextMethod("moveTo", args); + } + quadraticCurveTo(...args) { + return this._callContextMethod("quadraticCurveTo", args); + } + rect(...args) { + return this._callContextMethod("rect", args); + } + roundRect(...args) { + return this._callContextMethod("roundRect", args); + } + poly(...args) { + return this._callContextMethod("poly", args); + } + regularPoly(...args) { + return this._callContextMethod("regularPoly", args); + } + roundPoly(...args) { + return this._callContextMethod("roundPoly", args); + } + roundShape(...args) { + return this._callContextMethod("roundShape", args); + } + filletRect(...args) { + return this._callContextMethod("filletRect", args); + } + chamferRect(...args) { + return this._callContextMethod("chamferRect", args); + } + star(...args) { + return this._callContextMethod("star", args); + } + svg(...args) { + return this._callContextMethod("svg", args); + } + restore(...args) { + return this._callContextMethod("restore", args); + } + /** Saves the current graphics state, including transformations, fill styles, and stroke styles, onto a stack. */ + save() { + return this._callContextMethod("save", []); + } + /** + * Returns the current transformation matrix of the graphics context. + * @returns The current transformation matrix. + */ + getTransform() { + return this.context.getTransform(); + } + /** + * Resets the current transformation matrix to the identity matrix, effectively removing + * any transformations (rotation, scaling, translation) previously applied. + * @returns The instance of the current GraphicsContext for method chaining. + */ + resetTransform() { + return this._callContextMethod("resetTransform", []); + } + rotateTransform(...args) { + return this._callContextMethod("rotate", args); + } + scaleTransform(...args) { + return this._callContextMethod("scale", args); + } + setTransform(...args) { + return this._callContextMethod("setTransform", args); + } + transform(...args) { + return this._callContextMethod("transform", args); + } + translateTransform(...args) { + return this._callContextMethod("translate", args); + } + /** + * Clears all drawing commands from the graphics context, effectively resetting it. This includes clearing the path, + * and optionally resetting transformations to the identity matrix. + * @returns The instance of the current GraphicsContext for method chaining. + */ + clear() { + return this._callContextMethod("clear", []); + } + /** + * The fill style to use. + * @type {ConvertedFillStyle} + */ + get fillStyle() { + return this._context.fillStyle; + } + set fillStyle(value) { + this._context.fillStyle = value; + } + /** + * The stroke style to use. + * @type {ConvertedStrokeStyle} + */ + get strokeStyle() { + return this._context.strokeStyle; + } + set strokeStyle(value) { + this._context.strokeStyle = value; + } + /** + * Creates a new Graphics object. + * Note that only the context of the object is cloned, not its transform (position,scale,etc) + * @param deep - Whether to create a deep clone of the graphics object. If false, the context + * will be shared between the two objects (default false). If true, the context will be + * cloned (recommended if you need to modify the context in any way). + * @returns - A clone of the graphics object + */ + clone(deep = false) { + if (deep) { + return new Graphics(this._context.clone()); + } + this._ownedContext = null; + const clone = new Graphics(this._context); + return clone; + } + // -------- v7 deprecations --------- + /** + * @param width + * @param color + * @param alpha + * @deprecated since 8.0.0 Use {@link Graphics#setStrokeStyle} instead + */ + lineStyle(width, color, alpha) { + deprecation(v8_0_0, "Graphics#lineStyle is no longer needed. Use Graphics#setStrokeStyle to set the stroke style."); + const strokeStyle = {}; + width && (strokeStyle.width = width); + color && (strokeStyle.color = color); + alpha && (strokeStyle.alpha = alpha); + this.context.strokeStyle = strokeStyle; + return this; + } + /** + * @param color + * @param alpha + * @deprecated since 8.0.0 Use {@link Graphics#fill} instead + */ + beginFill(color, alpha) { + deprecation(v8_0_0, "Graphics#beginFill is no longer needed. Use Graphics#fill to fill the shape with the desired style."); + const fillStyle = {}; + color && (fillStyle.color = color); + alpha && (fillStyle.alpha = alpha); + this.context.fillStyle = fillStyle; + return this; + } + /** + * @deprecated since 8.0.0 Use {@link Graphics#fill} instead + */ + endFill() { + deprecation(v8_0_0, "Graphics#endFill is no longer needed. Use Graphics#fill to fill the shape with the desired style."); + this.context.fill(); + const strokeStyle = this.context.strokeStyle; + if (strokeStyle.width !== GraphicsContext.defaultStrokeStyle.width || strokeStyle.color !== GraphicsContext.defaultStrokeStyle.color || strokeStyle.alpha !== GraphicsContext.defaultStrokeStyle.alpha) { + this.context.stroke(); + } + return this; + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#circle} instead + */ + drawCircle(...args) { + deprecation(v8_0_0, "Graphics#drawCircle has been renamed to Graphics#circle"); + return this._callContextMethod("circle", args); + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#ellipse} instead + */ + drawEllipse(...args) { + deprecation(v8_0_0, "Graphics#drawEllipse has been renamed to Graphics#ellipse"); + return this._callContextMethod("ellipse", args); + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#poly} instead + */ + drawPolygon(...args) { + deprecation(v8_0_0, "Graphics#drawPolygon has been renamed to Graphics#poly"); + return this._callContextMethod("poly", args); + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#rect} instead + */ + drawRect(...args) { + deprecation(v8_0_0, "Graphics#drawRect has been renamed to Graphics#rect"); + return this._callContextMethod("rect", args); + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#roundRect} instead + */ + drawRoundedRect(...args) { + deprecation(v8_0_0, "Graphics#drawRoundedRect has been renamed to Graphics#roundRect"); + return this._callContextMethod("roundRect", args); + } + /** + * @param {...any} args + * @deprecated since 8.0.0 Use {@link Graphics#star} instead + */ + drawStar(...args) { + deprecation(v8_0_0, "Graphics#drawStar has been renamed to Graphics#star"); + return this._callContextMethod("star", args); + } + } + + "use strict"; + let maxFragmentPrecision; + function getMaxFragmentPrecision() { + if (!maxFragmentPrecision) { + maxFragmentPrecision = "mediump"; + const gl = getTestContext(); + if (gl) { + if (gl.getShaderPrecisionFormat) { + const shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT); + maxFragmentPrecision = shaderFragment.precision ? "highp" : "mediump"; + } + } + } + return maxFragmentPrecision; + } + + "use strict"; + function addProgramDefines(src, isES300, isFragment) { + if (isES300) + return src; + if (isFragment) { + src = src.replace("out vec4 finalColor;", ""); + return ` + + #ifdef GL_ES // This checks if it is WebGL1 + #define in varying + #define finalColor gl_FragColor + #define texture texture2D + #endif + ${src} + `; + } + return ` + + #ifdef GL_ES // This checks if it is WebGL1 + #define in attribute + #define out varying + #endif + ${src} + `; + } + + "use strict"; + function ensurePrecision(src, options, isFragment) { + const maxSupportedPrecision = isFragment ? options.maxSupportedFragmentPrecision : options.maxSupportedVertexPrecision; + if (src.substring(0, 9) !== "precision") { + let precision = isFragment ? options.requestedFragmentPrecision : options.requestedVertexPrecision; + if (precision === "highp" && maxSupportedPrecision !== "highp") { + precision = "mediump"; + } + return `precision ${precision} float; +${src}`; + } else if (maxSupportedPrecision !== "highp" && src.substring(0, 15) === "precision highp") { + return src.replace("precision highp", "precision mediump"); + } + return src; + } + + "use strict"; + function insertVersion(src, isES300) { + if (!isES300) + return src; + return `#version 300 es +${src}`; + } + + "use strict"; + const fragmentNameCache = {}; + const VertexNameCache = {}; + function setProgramName(src, { name = `pixi-program` }, isFragment = true) { + name = name.replace(/\s+/g, "-"); + name += isFragment ? "-fragment" : "-vertex"; + const nameCache = isFragment ? fragmentNameCache : VertexNameCache; + if (nameCache[name]) { + nameCache[name]++; + name += `-${nameCache[name]}`; + } else { + nameCache[name] = 1; + } + if (src.indexOf("#define SHADER_NAME") !== -1) + return src; + const shaderName = `#define SHADER_NAME ${name}`; + return `${shaderName} +${src}`; + } + + "use strict"; + function stripVersion(src, isES300) { + if (!isES300) + return src; + return src.replace("#version 300 es", ""); + } + + "use strict"; + var __defProp$M = Object.defineProperty; + var __getOwnPropSymbols$M = Object.getOwnPropertySymbols; + var __hasOwnProp$M = Object.prototype.hasOwnProperty; + var __propIsEnum$M = Object.prototype.propertyIsEnumerable; + var __defNormalProp$M = (obj, key, value) => key in obj ? __defProp$M(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$M = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$M.call(b, prop)) + __defNormalProp$M(a, prop, b[prop]); + if (__getOwnPropSymbols$M) + for (var prop of __getOwnPropSymbols$M(b)) { + if (__propIsEnum$M.call(b, prop)) + __defNormalProp$M(a, prop, b[prop]); + } + return a; + }; + const processes = { + // strips any version headers.. + stripVersion, + // adds precision string if not already present + ensurePrecision, + // add some defines if WebGL1 to make it more compatible with WebGL2 shaders + addProgramDefines, + // add the program name to the shader + setProgramName, + // add the version string to the shader header + insertVersion + }; + const programCache$1 = /* @__PURE__ */ Object.create(null); + const _GlProgram = class _GlProgram { + /** + * Creates a shiny new GlProgram. Used by WebGL renderer. + * @param options - The options for the program. + */ + constructor(options) { + options = __spreadValues$M(__spreadValues$M({}, _GlProgram.defaultOptions), options); + const isES300 = options.fragment.indexOf("#version 300 es") !== -1; + const preprocessorOptions = { + stripVersion: isES300, + ensurePrecision: { + requestedFragmentPrecision: options.preferredFragmentPrecision, + requestedVertexPrecision: options.preferredVertexPrecision, + maxSupportedVertexPrecision: "highp", + maxSupportedFragmentPrecision: getMaxFragmentPrecision() + }, + setProgramName: { + name: options.name + }, + addProgramDefines: isES300, + insertVersion: isES300 + }; + let fragment = options.fragment; + let vertex = options.vertex; + Object.keys(processes).forEach((processKey) => { + const processOptions = preprocessorOptions[processKey]; + fragment = processes[processKey](fragment, processOptions, true); + vertex = processes[processKey](vertex, processOptions, false); + }); + this.fragment = fragment; + this.vertex = vertex; + this._key = createIdFromString(`${this.vertex}:${this.fragment}`, "gl-program"); + } + /** destroys the program */ + destroy() { + this.fragment = null; + this.vertex = null; + this._attributeData = null; + this._uniformData = null; + this._uniformBlockData = null; + this.transformFeedbackVaryings = null; + } + /** + * Helper function that creates a program for a given source. + * It will check the program cache if the program has already been created. + * If it has that one will be returned, if not a new one will be created and cached. + * @param options - The options for the program. + * @returns A program using the same source + */ + static from(options) { + const key = `${options.vertex}:${options.fragment}`; + if (!programCache$1[key]) { + programCache$1[key] = new _GlProgram(options); + } + return programCache$1[key]; + } + }; + /** The default options used by the program. */ + _GlProgram.defaultOptions = { + preferredVertexPrecision: "highp", + preferredFragmentPrecision: "mediump" + }; + let GlProgram = _GlProgram; + + "use strict"; + const attributeFormatData = { + uint8x2: { size: 2, stride: 2, normalised: false }, + uint8x4: { size: 4, stride: 4, normalised: false }, + sint8x2: { size: 2, stride: 2, normalised: false }, + sint8x4: { size: 4, stride: 4, normalised: false }, + unorm8x2: { size: 2, stride: 2, normalised: true }, + unorm8x4: { size: 4, stride: 4, normalised: true }, + snorm8x2: { size: 2, stride: 2, normalised: true }, + snorm8x4: { size: 4, stride: 4, normalised: true }, + uint16x2: { size: 2, stride: 4, normalised: false }, + uint16x4: { size: 4, stride: 8, normalised: false }, + sint16x2: { size: 2, stride: 4, normalised: false }, + sint16x4: { size: 4, stride: 8, normalised: false }, + unorm16x2: { size: 2, stride: 4, normalised: true }, + unorm16x4: { size: 4, stride: 8, normalised: true }, + snorm16x2: { size: 2, stride: 4, normalised: true }, + snorm16x4: { size: 4, stride: 8, normalised: true }, + float16x2: { size: 2, stride: 4, normalised: false }, + float16x4: { size: 4, stride: 8, normalised: false }, + float32: { size: 1, stride: 4, normalised: false }, + float32x2: { size: 2, stride: 8, normalised: false }, + float32x3: { size: 3, stride: 12, normalised: false }, + float32x4: { size: 4, stride: 16, normalised: false }, + uint32: { size: 1, stride: 4, normalised: false }, + uint32x2: { size: 2, stride: 8, normalised: false }, + uint32x3: { size: 3, stride: 12, normalised: false }, + uint32x4: { size: 4, stride: 16, normalised: false }, + sint32: { size: 1, stride: 4, normalised: false }, + sint32x2: { size: 2, stride: 8, normalised: false }, + sint32x3: { size: 3, stride: 12, normalised: false }, + sint32x4: { size: 4, stride: 16, normalised: false } + }; + function getAttributeInfoFromFormat(format) { + var _a; + return (_a = attributeFormatData[format]) != null ? _a : attributeFormatData.float32; + } + + "use strict"; + const WGSL_TO_VERTEX_TYPES = { + f32: "float32", + "vec2": "float32x2", + "vec3": "float32x3", + "vec4": "float32x4", + vec2f: "float32x2", + vec3f: "float32x3", + vec4f: "float32x4", + i32: "sint32", + "vec2": "sint32x2", + "vec3": "sint32x3", + "vec4": "sint32x4", + u32: "uint32", + "vec2": "uint32x2", + "vec3": "uint32x3", + "vec4": "uint32x4", + bool: "uint32", + "vec2": "uint32x2", + "vec3": "uint32x3", + "vec4": "uint32x4" + }; + function extractAttributesFromGpuProgram({ source, entryPoint }) { + var _a; + const results = {}; + const mainVertStart = source.indexOf(`fn ${entryPoint}`); + if (mainVertStart !== -1) { + const arrowFunctionStart = source.indexOf("->", mainVertStart); + if (arrowFunctionStart !== -1) { + const functionArgsSubstring = source.substring(mainVertStart, arrowFunctionStart); + const inputsRegex = /@location\((\d+)\)\s+([a-zA-Z0-9_]+)\s*:\s*([a-zA-Z0-9_<>]+)(?:,|\s|$)/g; + let match; + while ((match = inputsRegex.exec(functionArgsSubstring)) !== null) { + const format = (_a = WGSL_TO_VERTEX_TYPES[match[3]]) != null ? _a : "float32"; + results[match[2]] = { + location: parseInt(match[1], 10), + format, + stride: getAttributeInfoFromFormat(format).stride, + offset: 0, + instance: false, + start: 0 + }; + } + } + } + return results; + } + + "use strict"; + function extractStructAndGroups(wgsl) { + var _a, _b, _c; + const linePattern = /(^|[^/])@(group|binding)\(\d+\)[^;]+;/g; + const groupPattern = /@group\((\d+)\)/; + const bindingPattern = /@binding\((\d+)\)/; + const namePattern = /var(<[^>]+>)? (\w+)/; + const typePattern = /:\s*(\w+)/; + const structPattern = /struct\s+(\w+)\s*{([^}]+)}/g; + const structMemberPattern = /(\w+)\s*:\s*([\w\<\>]+)/g; + const structName = /struct\s+(\w+)/; + const groups = (_a = wgsl.match(linePattern)) == null ? void 0 : _a.map((item) => ({ + group: parseInt(item.match(groupPattern)[1], 10), + binding: parseInt(item.match(bindingPattern)[1], 10), + name: item.match(namePattern)[2], + isUniform: item.match(namePattern)[1] === "", + type: item.match(typePattern)[1] + })); + if (!groups) { + return { + groups: [], + structs: [] + }; + } + const structs = (_c = (_b = wgsl.match(structPattern)) == null ? void 0 : _b.map((struct) => { + const name = struct.match(structName)[1]; + const members = struct.match(structMemberPattern).reduce((acc, member) => { + const [name2, type] = member.split(":"); + acc[name2.trim()] = type.trim(); + return acc; + }, {}); + if (!members) { + return null; + } + return { name, members }; + }).filter(({ name }) => groups.some((group) => group.type === name))) != null ? _c : []; + return { + groups, + structs + }; + } + + "use strict"; + var ShaderStage = /* @__PURE__ */ ((ShaderStage2) => { + ShaderStage2[ShaderStage2["VERTEX"] = 1] = "VERTEX"; + ShaderStage2[ShaderStage2["FRAGMENT"] = 2] = "FRAGMENT"; + ShaderStage2[ShaderStage2["COMPUTE"] = 4] = "COMPUTE"; + return ShaderStage2; + })(ShaderStage || {}); + + "use strict"; + function generateGpuLayoutGroups({ groups }) { + const layout = []; + for (let i = 0; i < groups.length; i++) { + const group = groups[i]; + if (!layout[group.group]) { + layout[group.group] = []; + } + if (group.isUniform) { + layout[group.group].push({ + binding: group.binding, + visibility: ShaderStage.VERTEX | ShaderStage.FRAGMENT, + buffer: { + type: "uniform" + } + }); + } else if (group.type === "sampler") { + layout[group.group].push({ + binding: group.binding, + visibility: ShaderStage.FRAGMENT, + sampler: { + type: "filtering" + } + }); + } else if (group.type === "texture_2d") { + layout[group.group].push({ + binding: group.binding, + visibility: ShaderStage.FRAGMENT, + texture: { + sampleType: "float", + viewDimension: "2d", + multisampled: false + } + }); + } + } + return layout; + } + + "use strict"; + function generateLayoutHash({ groups }) { + const layout = []; + for (let i = 0; i < groups.length; i++) { + const group = groups[i]; + if (!layout[group.group]) { + layout[group.group] = {}; + } + layout[group.group][group.name] = group.binding; + } + return layout; + } + + "use strict"; + function removeStructAndGroupDuplicates(vertexStructsAndGroups, fragmentStructsAndGroups) { + const structNameSet = /* @__PURE__ */ new Set(); + const dupeGroupKeySet = /* @__PURE__ */ new Set(); + const structs = [...vertexStructsAndGroups.structs, ...fragmentStructsAndGroups.structs].filter((struct) => { + if (structNameSet.has(struct.name)) { + return false; + } + structNameSet.add(struct.name); + return true; + }); + const groups = [...vertexStructsAndGroups.groups, ...fragmentStructsAndGroups.groups].filter((group) => { + const key = `${group.name}-${group.binding}`; + if (dupeGroupKeySet.has(key)) { + return false; + } + dupeGroupKeySet.add(key); + return true; + }); + return { structs, groups }; + } + + "use strict"; + const programCache = /* @__PURE__ */ Object.create(null); + class GpuProgram { + /** + * Create a new GpuProgram + * @param options - The options for the gpu program + */ + constructor(options) { + /** + * @internal + * @ignore + */ + this._layoutKey = 0; + var _a, _b; + const { fragment, vertex, layout, gpuLayout, name } = options; + this.name = name; + this.fragment = fragment; + this.vertex = vertex; + if (fragment.source === vertex.source) { + const structsAndGroups = extractStructAndGroups(fragment.source); + this.structsAndGroups = structsAndGroups; + } else { + const vertexStructsAndGroups = extractStructAndGroups(vertex.source); + const fragmentStructsAndGroups = extractStructAndGroups(fragment.source); + this.structsAndGroups = removeStructAndGroupDuplicates(vertexStructsAndGroups, fragmentStructsAndGroups); + } + this.layout = layout != null ? layout : generateLayoutHash(this.structsAndGroups); + this.gpuLayout = gpuLayout != null ? gpuLayout : generateGpuLayoutGroups(this.structsAndGroups); + this.autoAssignGlobalUniforms = !!(((_a = this.layout[0]) == null ? void 0 : _a.globalUniforms) !== void 0); + this.autoAssignLocalUniforms = !!(((_b = this.layout[1]) == null ? void 0 : _b.localUniforms) !== void 0); + this._generateProgramKey(); + } + // TODO maker this pure + _generateProgramKey() { + const { vertex, fragment } = this; + const bigKey = vertex.source + fragment.source + vertex.entryPoint + fragment.entryPoint; + this._layoutKey = createIdFromString(bigKey, "program"); + } + get attributeData() { + var _a; + (_a = this._attributeData) != null ? _a : this._attributeData = extractAttributesFromGpuProgram(this.vertex); + return this._attributeData; + } + /** destroys the program */ + destroy() { + this.gpuLayout = null; + this.layout = null; + this.structsAndGroups = null; + this.fragment = null; + this.vertex = null; + } + /** + * Helper function that creates a program for a given source. + * It will check the program cache if the program has already been created. + * If it has that one will be returned, if not a new one will be created and cached. + * @param options - The options for the program. + * @returns A program using the same source + */ + static from(options) { + const key = `${options.vertex.source}:${options.fragment.source}:${options.fragment.entryPoint}:${options.vertex.entryPoint}`; + if (!programCache[key]) { + programCache[key] = new GpuProgram(options); + } + return programCache[key]; + } + } + + "use strict"; + function addBits(srcParts, parts, name) { + if (srcParts) { + for (const i in srcParts) { + const id = i.toLocaleLowerCase(); + const part = parts[id]; + if (part) { + let sanitisedPart = srcParts[i]; + if (i === "header") { + sanitisedPart = sanitisedPart.replace(/@in\s+[^;]+;\s*/g, "").replace(/@out\s+[^;]+;\s*/g, ""); + } + if (name) { + part.push(`//----${name}----//`); + } + part.push(sanitisedPart); + } else { + warn(`${i} placement hook does not exist in shader`); + } + } + } + } + + "use strict"; + const findHooksRx = /\{\{(.*?)\}\}/g; + function compileHooks(programSrc) { + var _a, _b; + const parts = {}; + const partMatches = (_b = (_a = programSrc.match(findHooksRx)) == null ? void 0 : _a.map((hook) => hook.replace(/[{()}]/g, ""))) != null ? _b : []; + partMatches.forEach((hook) => { + parts[hook] = []; + }); + return parts; + } + + "use strict"; + function extractInputs(fragmentSource, out) { + let match; + const regex = /@in\s+([^;]+);/g; + while ((match = regex.exec(fragmentSource)) !== null) { + out.push(match[1]); + } + } + function compileInputs(fragments, template, sort = false) { + const results = []; + extractInputs(template, results); + fragments.forEach((fragment) => { + if (fragment.header) { + extractInputs(fragment.header, results); + } + }); + const mainInput = results; + if (sort) { + mainInput.sort(); + } + const finalString = mainInput.map((inValue, i) => ` @location(${i}) ${inValue},`).join("\n"); + let cleanedString = template.replace(/@in\s+[^;]+;\s*/g, ""); + cleanedString = cleanedString.replace("{{in}}", ` +${finalString} +`); + return cleanedString; + } + + "use strict"; + function extractOutputs(fragmentSource, out) { + let match; + const regex = /@out\s+([^;]+);/g; + while ((match = regex.exec(fragmentSource)) !== null) { + out.push(match[1]); + } + } + function extractVariableName(value) { + const regex = /\b(\w+)\s*:/g; + const match = regex.exec(value); + return match ? match[1] : ""; + } + function stripVariable(value) { + const regex = /@.*?\s+/g; + return value.replace(regex, ""); + } + function compileOutputs(fragments, template) { + const results = []; + extractOutputs(template, results); + fragments.forEach((fragment) => { + if (fragment.header) { + extractOutputs(fragment.header, results); + } + }); + let index = 0; + const mainStruct = results.sort().map((inValue) => { + if (inValue.indexOf("builtin") > -1) { + return inValue; + } + return `@location(${index++}) ${inValue}`; + }).join(",\n"); + const mainStart = results.sort().map((inValue) => ` var ${stripVariable(inValue)};`).join("\n"); + const mainEnd = `return VSOutput( + ${results.sort().map((inValue) => ` ${extractVariableName(inValue)}`).join(",\n")});`; + let compiledCode = template.replace(/@out\s+[^;]+;\s*/g, ""); + compiledCode = compiledCode.replace("{{struct}}", ` +${mainStruct} +`); + compiledCode = compiledCode.replace("{{start}}", ` +${mainStart} +`); + compiledCode = compiledCode.replace("{{return}}", ` +${mainEnd} +`); + return compiledCode; + } + + "use strict"; + function injectBits(templateSrc, fragmentParts) { + let out = templateSrc; + for (const i in fragmentParts) { + const parts = fragmentParts[i]; + const toInject = parts.join("\n"); + if (toInject.length) { + out = out.replace(`{{${i}}}`, `//-----${i} START-----// +${parts.join("\n")} +//----${i} FINISH----//`); + } else { + out = out.replace(`{{${i}}}`, ""); + } + } + return out; + } + + "use strict"; + const cacheMap = /* @__PURE__ */ Object.create(null); + const bitCacheMap = /* @__PURE__ */ new Map(); + let CACHE_UID = 0; + function compileHighShader({ + template, + bits + }) { + const cacheId = generateCacheId(template, bits); + if (cacheMap[cacheId]) + return cacheMap[cacheId]; + const { vertex, fragment } = compileInputsAndOutputs(template, bits); + cacheMap[cacheId] = compileBits(vertex, fragment, bits); + return cacheMap[cacheId]; + } + function compileHighShaderGl({ + template, + bits + }) { + const cacheId = generateCacheId(template, bits); + if (cacheMap[cacheId]) + return cacheMap[cacheId]; + cacheMap[cacheId] = compileBits(template.vertex, template.fragment, bits); + return cacheMap[cacheId]; + } + function compileInputsAndOutputs(template, bits) { + const vertexFragments = bits.map((shaderBit) => shaderBit.vertex).filter((v) => !!v); + const fragmentFragments = bits.map((shaderBit) => shaderBit.fragment).filter((v) => !!v); + let compiledVertex = compileInputs(vertexFragments, template.vertex, true); + compiledVertex = compileOutputs(vertexFragments, compiledVertex); + const compiledFragment = compileInputs(fragmentFragments, template.fragment, true); + return { + vertex: compiledVertex, + fragment: compiledFragment + }; + } + function generateCacheId(template, bits) { + return bits.map((highFragment) => { + if (!bitCacheMap.has(highFragment)) { + bitCacheMap.set(highFragment, CACHE_UID++); + } + return bitCacheMap.get(highFragment); + }).sort((a, b) => a - b).join("-") + template.vertex + template.fragment; + } + function compileBits(vertex, fragment, bits) { + const vertexParts = compileHooks(vertex); + const fragmentParts = compileHooks(fragment); + bits.forEach((shaderBit) => { + addBits(shaderBit.vertex, vertexParts, shaderBit.name); + addBits(shaderBit.fragment, fragmentParts, shaderBit.name); + }); + return { + vertex: injectBits(vertex, vertexParts), + fragment: injectBits(fragment, fragmentParts) + }; + } + + "use strict"; + const vertexGPUTemplate = ( + /* wgsl */ + ` + @in aPosition: vec2; + @in aUV: vec2; + + @out @builtin(position) vPosition: vec4; + @out vUV : vec2; + @out vColor : vec4; + + {{header}} + + struct VSOutput { + {{struct}} + }; + + @vertex + fn main( {{in}} ) -> VSOutput { + + var worldTransformMatrix = globalUniforms.uWorldTransformMatrix; + var modelMatrix = mat3x3( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + ); + var position = aPosition; + var uv = aUV; + + {{start}} + + vColor = vec4(1., 1., 1., 1.); + + {{main}} + + vUV = uv; + + var modelViewProjectionMatrix = globalUniforms.uProjectionMatrix * worldTransformMatrix * modelMatrix; + + vPosition = vec4((modelViewProjectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0); + + vColor *= globalUniforms.uWorldColorAlpha; + + {{end}} + + {{return}} + }; +` + ); + const fragmentGPUTemplate = ( + /* wgsl */ + ` + @in vUV : vec2; + @in vColor : vec4; + + {{header}} + + @fragment + fn main( + {{in}} + ) -> @location(0) vec4 { + + {{start}} + + var outColor:vec4; + + {{main}} + + return outColor * vColor; + }; +` + ); + const vertexGlTemplate = ( + /* glsl */ + ` + in vec2 aPosition; + in vec2 aUV; + + out vec4 vColor; + out vec2 vUV; + + {{header}} + + void main(void){ + + mat3 worldTransformMatrix = uWorldTransformMatrix; + mat3 modelMatrix = mat3( + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 + ); + vec2 position = aPosition; + vec2 uv = aUV; + + {{start}} + + vColor = vec4(1.); + + {{main}} + + vUV = uv; + + mat3 modelViewProjectionMatrix = uProjectionMatrix * worldTransformMatrix * modelMatrix; + + gl_Position = vec4((modelViewProjectionMatrix * vec3(position, 1.0)).xy, 0.0, 1.0); + + vColor *= uWorldColorAlpha; + + {{end}} + } +` + ); + const fragmentGlTemplate = ( + /* glsl */ + ` + + in vec4 vColor; + in vec2 vUV; + + out vec4 finalColor; + + {{header}} + + void main(void) { + + {{start}} + + vec4 outColor; + + {{main}} + + finalColor = outColor * vColor; + } +` + ); + + "use strict"; + const globalUniformsBit = { + name: "global-uniforms-bit", + vertex: { + header: ( + /* wgsl */ + ` + struct GlobalUniforms { + uProjectionMatrix:mat3x3, + uWorldTransformMatrix:mat3x3, + uWorldColorAlpha: vec4, + uResolution: vec2, + } + + @group(0) @binding(0) var globalUniforms : GlobalUniforms; + ` + ) + } + }; + const globalUniformsUBOBitGl = { + name: "global-uniforms-ubo-bit", + vertex: { + header: ( + /* glsl */ + ` + uniform globalUniforms { + mat3 uProjectionMatrix; + mat3 uWorldTransformMatrix; + vec4 uWorldColorAlpha; + vec2 uResolution; + }; + ` + ) + } + }; + const globalUniformsBitGl = { + name: "global-uniforms-bit", + vertex: { + header: ( + /* glsl */ + ` + uniform mat3 uProjectionMatrix; + uniform mat3 uWorldTransformMatrix; + uniform vec4 uWorldColorAlpha; + uniform vec2 uResolution; + ` + ) + } + }; + + "use strict"; + var __defProp$L = Object.defineProperty; + var __getOwnPropSymbols$L = Object.getOwnPropertySymbols; + var __hasOwnProp$L = Object.prototype.hasOwnProperty; + var __propIsEnum$L = Object.prototype.propertyIsEnumerable; + var __defNormalProp$L = (obj, key, value) => key in obj ? __defProp$L(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$L = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$L.call(b, prop)) + __defNormalProp$L(a, prop, b[prop]); + if (__getOwnPropSymbols$L) + for (var prop of __getOwnPropSymbols$L(b)) { + if (__propIsEnum$L.call(b, prop)) + __defNormalProp$L(a, prop, b[prop]); + } + return a; + }; + function compileHighShaderGpuProgram({ bits, name }) { + const source = compileHighShader({ + template: { + fragment: fragmentGPUTemplate, + vertex: vertexGPUTemplate + }, + bits: [ + globalUniformsBit, + ...bits + ] + }); + return GpuProgram.from({ + name, + vertex: { + source: source.vertex, + entryPoint: "main" + }, + fragment: { + source: source.fragment, + entryPoint: "main" + } + }); + } + function compileHighShaderGlProgram({ bits, name }) { + return new GlProgram(__spreadValues$L({ + name + }, compileHighShaderGl({ + template: { + vertex: vertexGlTemplate, + fragment: fragmentGlTemplate + }, + bits: [ + globalUniformsBitGl, + ...bits + ] + }))); + } + + "use strict"; + const colorBit = { + name: "color-bit", + vertex: { + header: ( + /* wgsl */ + ` + @in aColor: vec4; + ` + ), + main: ( + /* wgsl */ + ` + vColor *= vec4(aColor.rgb * aColor.a, aColor.a); + ` + ) + } + }; + const colorBitGl = { + name: "color-bit", + vertex: { + header: ( + /* glsl */ + ` + in vec4 aColor; + ` + ), + main: ( + /* glsl */ + ` + vColor *= vec4(aColor.rgb * aColor.a, aColor.a); + ` + ) + } + }; + + "use strict"; + const textureBatchBitGpuCache = {}; + function generateBindingSrc(maxTextures) { + const src = []; + if (maxTextures === 1) { + src.push("@group(1) @binding(0) var textureSource1: texture_2d;"); + src.push("@group(1) @binding(1) var textureSampler1: sampler;"); + } else { + let bindingIndex = 0; + for (let i = 0; i < maxTextures; i++) { + src.push(`@group(1) @binding(${bindingIndex++}) var textureSource${i + 1}: texture_2d;`); + src.push(`@group(1) @binding(${bindingIndex++}) var textureSampler${i + 1}: sampler;`); + } + } + return src.join("\n"); + } + function generateSampleSrc(maxTextures) { + const src = []; + if (maxTextures === 1) { + src.push("outColor = textureSampleGrad(textureSource1, textureSampler1, vUV, uvDx, uvDy);"); + } else { + src.push("switch vTextureId {"); + for (let i = 0; i < maxTextures; i++) { + if (i === maxTextures - 1) { + src.push(` default:{`); + } else { + src.push(` case ${i}:{`); + } + src.push(` outColor = textureSampleGrad(textureSource${i + 1}, textureSampler${i + 1}, vUV, uvDx, uvDy);`); + src.push(` break;}`); + } + src.push(`}`); + } + return src.join("\n"); + } + function generateTextureBatchBit(maxTextures) { + if (!textureBatchBitGpuCache[maxTextures]) { + textureBatchBitGpuCache[maxTextures] = { + name: "texture-batch-bit", + vertex: { + header: ` + @in aTextureIdAndRound: vec2; + @out @interpolate(flat) vTextureId : u32; + `, + main: ` + vTextureId = aTextureIdAndRound.y; + `, + end: ` + if(aTextureIdAndRound.x == 1) + { + vPosition = vec4(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw); + } + ` + }, + fragment: { + header: ` + @in @interpolate(flat) vTextureId: u32; + + ${generateBindingSrc(maxRecommendedTextures())} + `, + main: ` + var uvDx = dpdx(vUV); + var uvDy = dpdy(vUV); + + ${generateSampleSrc(maxRecommendedTextures())} + ` + } + }; + } + return textureBatchBitGpuCache[maxTextures]; + } + const textureBatchBitGlCache = {}; + function generateSampleGlSrc(maxTextures) { + const src = []; + for (let i = 0; i < maxTextures; i++) { + if (i > 0) { + src.push("else"); + } + if (i < maxTextures - 1) { + src.push(`if(vTextureId < ${i}.5)`); + } + src.push("{"); + src.push(` outColor = texture(uTextures[${i}], vUV);`); + src.push("}"); + } + return src.join("\n"); + } + function generateTextureBatchBitGl(maxTextures) { + if (!textureBatchBitGlCache[maxTextures]) { + textureBatchBitGlCache[maxTextures] = { + name: "texture-batch-bit", + vertex: { + header: ` + in vec2 aTextureIdAndRound; + out float vTextureId; + + `, + main: ` + vTextureId = aTextureIdAndRound.y; + `, + end: ` + if(aTextureIdAndRound.x == 1.) + { + gl_Position.xy = roundPixels(gl_Position.xy, uResolution); + } + ` + }, + fragment: { + header: ` + in float vTextureId; + + uniform sampler2D uTextures[${maxTextures}]; + + `, + main: ` + + ${generateSampleGlSrc(maxRecommendedTextures())} + ` + } + }; + } + return textureBatchBitGlCache[maxTextures]; + } + + "use strict"; + const roundPixelsBit = { + name: "round-pixels-bit", + vertex: { + header: ( + /* wgsl */ + ` + fn roundPixels(position: vec2, targetSize: vec2) -> vec2 + { + return (floor(((position * 0.5 + 0.5) * targetSize) + 0.5) / targetSize) * 2.0 - 1.0; + } + ` + ) + } + }; + const roundPixelsBitGl = { + name: "round-pixels-bit", + vertex: { + header: ( + /* glsl */ + ` + vec2 roundPixels(vec2 position, vec2 targetSize) + { + return (floor(((position * 0.5 + 0.5) * targetSize) + 0.5) / targetSize) * 2.0 - 1.0; + } + ` + ) + } + }; + + "use strict"; + const batchSamplersUniformGroupHash = {}; + function getBatchSamplersUniformGroup(maxTextures) { + let batchSamplersUniformGroup = batchSamplersUniformGroupHash[maxTextures]; + if (batchSamplersUniformGroup) + return batchSamplersUniformGroup; + const sampleValues = new Int32Array(maxTextures); + for (let i = 0; i < maxTextures; i++) { + sampleValues[i] = i; + } + batchSamplersUniformGroup = batchSamplersUniformGroupHash[maxTextures] = new UniformGroup({ + uTextures: { value: sampleValues, type: `i32`, size: maxTextures } + }, { isStatic: true }); + return batchSamplersUniformGroup; + } + + "use strict"; + var RendererType = /* @__PURE__ */ ((RendererType2) => { + RendererType2[RendererType2["WEBGL"] = 1] = "WEBGL"; + RendererType2[RendererType2["WEBGPU"] = 2] = "WEBGPU"; + RendererType2[RendererType2["BOTH"] = 3] = "BOTH"; + return RendererType2; + })(RendererType || {}); + + "use strict"; + var __defProp$K = Object.defineProperty; + var __getOwnPropSymbols$K = Object.getOwnPropertySymbols; + var __hasOwnProp$K = Object.prototype.hasOwnProperty; + var __propIsEnum$K = Object.prototype.propertyIsEnumerable; + var __defNormalProp$K = (obj, key, value) => key in obj ? __defProp$K(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$K = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$K.call(b, prop)) + __defNormalProp$K(a, prop, b[prop]); + if (__getOwnPropSymbols$K) + for (var prop of __getOwnPropSymbols$K(b)) { + if (__propIsEnum$K.call(b, prop)) + __defNormalProp$K(a, prop, b[prop]); + } + return a; + }; + var __objRest$f = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$K.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$K) + for (var prop of __getOwnPropSymbols$K(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$K.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class Shader extends EventEmitter { + constructor(options) { + super(); + /** + * A record of the uniform groups and resources used by the shader. + * This is used by WebGL renderer to sync uniform data. + * @internal + * @ignore + */ + this._uniformBindMap = /* @__PURE__ */ Object.create(null); + this._ownedBindGroups = []; + let { + gpuProgram, + glProgram, + groups, + resources, + compatibleRenderers, + groupMap + } = options; + this.gpuProgram = gpuProgram; + this.glProgram = glProgram; + if (compatibleRenderers === void 0) { + compatibleRenderers = 0; + if (gpuProgram) + compatibleRenderers |= RendererType.WEBGPU; + if (glProgram) + compatibleRenderers |= RendererType.WEBGL; + } + this.compatibleRenderers = compatibleRenderers; + const nameHash = {}; + if (!resources && !groups) { + resources = {}; + } + if (resources && groups) { + throw new Error("[Shader] Cannot have both resources and groups"); + } else if (!gpuProgram && groups && !groupMap) { + throw new Error("[Shader] No group map or WebGPU shader provided - consider using resources instead."); + } else if (!gpuProgram && groups && groupMap) { + for (const i in groupMap) { + for (const j in groupMap[i]) { + const uniformName = groupMap[i][j]; + nameHash[uniformName] = { + group: i, + binding: j, + name: uniformName + }; + } + } + } else if (gpuProgram && groups && !groupMap) { + const groupData = gpuProgram.structsAndGroups.groups; + groupMap = {}; + groupData.forEach((data) => { + groupMap[data.group] = groupMap[data.group] || {}; + groupMap[data.group][data.binding] = data.name; + nameHash[data.name] = data; + }); + } else if (resources) { + if (!gpuProgram) { + groupMap = {}; + groups = { + 99: new BindGroup() + }; + this._ownedBindGroups.push(groups[99]); + let bindTick = 0; + for (const i in resources) { + nameHash[i] = { group: 99, binding: bindTick, name: i }; + groupMap[99] = groupMap[99] || {}; + groupMap[99][bindTick] = i; + bindTick++; + } + } else { + const groupData = gpuProgram.structsAndGroups.groups; + groupMap = {}; + groupData.forEach((data) => { + groupMap[data.group] = groupMap[data.group] || {}; + groupMap[data.group][data.binding] = data.name; + nameHash[data.name] = data; + }); + } + groups = {}; + for (const i in resources) { + const name = i; + let value = resources[i]; + if (!value.source && !value._resourceType) { + value = new UniformGroup(value); + } + const data = nameHash[name]; + if (data) { + if (!groups[data.group]) { + groups[data.group] = new BindGroup(); + this._ownedBindGroups.push(groups[data.group]); + } + groups[data.group].setResource(value, data.binding); + } + } + } + this.groups = groups; + this._uniformBindMap = groupMap; + this.resources = this._buildResourceAccessor(groups, nameHash); + } + /** + * Sometimes a resource group will be provided later (for example global uniforms) + * In such cases, this method can be used to let the shader know about the group. + * @param name - the name of the resource group + * @param groupIndex - the index of the group (should match the webGPU shader group location) + * @param bindIndex - the index of the bind point (should match the webGPU shader bind point) + */ + addResource(name, groupIndex, bindIndex) { + var _a, _b; + (_a = this._uniformBindMap)[groupIndex] || (_a[groupIndex] = {}); + (_b = this._uniformBindMap[groupIndex])[bindIndex] || (_b[bindIndex] = name); + if (!this.groups[groupIndex]) { + this.groups[groupIndex] = new BindGroup(); + this._ownedBindGroups.push(this.groups[groupIndex]); + } + } + _buildResourceAccessor(groups, nameHash) { + const uniformsOut = {}; + for (const i in nameHash) { + const data = nameHash[i]; + Object.defineProperty(uniformsOut, data.name, { + get() { + return groups[data.group].getResource(data.binding); + }, + set(value) { + groups[data.group].setResource(value, data.binding); + } + }); + } + return uniformsOut; + } + /** + * Use to destroy the shader when its not longer needed. + * It will destroy the resources and remove listeners. + * @param destroyPrograms - if the programs should be destroyed as well. + * Make sure its not being used by other shaders! + */ + destroy(destroyPrograms = false) { + var _a, _b; + this.emit("destroy", this); + if (destroyPrograms) { + (_a = this.gpuProgram) == null ? void 0 : _a.destroy(); + (_b = this.glProgram) == null ? void 0 : _b.destroy(); + } + this.gpuProgram = null; + this.glProgram = null; + this.removeAllListeners(); + this._uniformBindMap = null; + this._ownedBindGroups.forEach((bindGroup) => { + bindGroup.destroy(); + }); + this._ownedBindGroups = null; + this.resources = null; + this.groups = null; + } + static from(options) { + const _a = options, { gpu, gl } = _a, rest = __objRest$f(_a, ["gpu", "gl"]); + let gpuProgram; + let glProgram; + if (gpu) { + gpuProgram = GpuProgram.from(gpu); + } + if (gl) { + glProgram = GlProgram.from(gl); + } + return new Shader(__spreadValues$K({ + gpuProgram, + glProgram + }, rest)); + } + } + + "use strict"; + const localUniformMSDFBit = { + name: "local-uniform-msdf-bit", + vertex: { + header: ( + /* wgsl */ + ` + struct LocalUniforms { + uColor:vec4, + uTransformMatrix:mat3x3, + uDistance: f32, + uRound:f32, + } + + @group(2) @binding(0) var localUniforms : LocalUniforms; + ` + ), + main: ( + /* wgsl */ + ` + vColor *= localUniforms.uColor; + modelMatrix *= localUniforms.uTransformMatrix; + ` + ), + end: ( + /* wgsl */ + ` + if(localUniforms.uRound == 1) + { + vPosition = vec4(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw); + } + ` + ) + }, + fragment: { + header: ( + /* wgsl */ + ` + struct LocalUniforms { + uColor:vec4, + uTransformMatrix:mat3x3, + uDistance: f32 + } + + @group(2) @binding(0) var localUniforms : LocalUniforms; + ` + ), + main: ( + /* wgsl */ + ` + outColor = vec4(calculateMSDFAlpha(outColor, localUniforms.uColor, localUniforms.uDistance)); + ` + ) + } + }; + const localUniformMSDFBitGl = { + name: "local-uniform-msdf-bit", + vertex: { + header: ( + /* glsl */ + ` + uniform mat3 uTransformMatrix; + uniform vec4 uColor; + uniform float uRound; + ` + ), + main: ( + /* glsl */ + ` + vColor *= uColor; + modelMatrix *= uTransformMatrix; + ` + ), + end: ( + /* glsl */ + ` + if(uRound == 1.) + { + gl_Position.xy = roundPixels(gl_Position.xy, uResolution); + } + ` + ) + }, + fragment: { + header: ( + /* glsl */ + ` + uniform float uDistance; + ` + ), + main: ( + /* glsl */ + ` + outColor = vec4(calculateMSDFAlpha(outColor, vColor, uDistance)); + ` + ) + } + }; + + "use strict"; + const mSDFBit = { + name: "msdf-bit", + fragment: { + header: ( + /* wgsl */ + ` + fn calculateMSDFAlpha(msdfColor:vec4, shapeColor:vec4, distance:f32) -> f32 { + + // MSDF + var median = msdfColor.r + msdfColor.g + msdfColor.b - + min(msdfColor.r, min(msdfColor.g, msdfColor.b)) - + max(msdfColor.r, max(msdfColor.g, msdfColor.b)); + + // SDF + median = min(median, msdfColor.a); + + var screenPxDistance = distance * (median - 0.5); + var alpha = clamp(screenPxDistance + 0.5, 0.0, 1.0); + if (median < 0.01) { + alpha = 0.0; + } else if (median > 0.99) { + alpha = 1.0; + } + + // Gamma correction for coverage-like alpha + var luma: f32 = dot(shapeColor.rgb, vec3(0.299, 0.587, 0.114)); + var gamma: f32 = mix(1.0, 1.0 / 2.2, luma); + var coverage: f32 = pow(shapeColor.a * alpha, gamma); + + return coverage; + + } + ` + ) + } + }; + const mSDFBitGl = { + name: "msdf-bit", + fragment: { + header: ( + /* glsl */ + ` + float calculateMSDFAlpha(vec4 msdfColor, vec4 shapeColor, float distance) { + + // MSDF + float median = msdfColor.r + msdfColor.g + msdfColor.b - + min(msdfColor.r, min(msdfColor.g, msdfColor.b)) - + max(msdfColor.r, max(msdfColor.g, msdfColor.b)); + + // SDF + median = min(median, msdfColor.a); + + float screenPxDistance = distance * (median - 0.5); + float alpha = clamp(screenPxDistance + 0.5, 0.0, 1.0); + + if (median < 0.01) { + alpha = 0.0; + } else if (median > 0.99) { + alpha = 1.0; + } + + // Gamma correction for coverage-like alpha + float luma = dot(shapeColor.rgb, vec3(0.299, 0.587, 0.114)); + float gamma = mix(1.0, 1.0 / 2.2, luma); + float coverage = pow(shapeColor.a * alpha, gamma); + + return coverage; + } + ` + ) + } + }; + + "use strict"; + let gpuProgram$1; + let glProgram$1; + class SdfShader extends Shader { + constructor() { + const uniforms = new UniformGroup({ + uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4" }, + uTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + uDistance: { value: 4, type: "f32" }, + uRound: { value: 0, type: "f32" } + }); + const maxTextures = maxRecommendedTextures(); + gpuProgram$1 != null ? gpuProgram$1 : gpuProgram$1 = compileHighShaderGpuProgram({ + name: "sdf-shader", + bits: [ + colorBit, + generateTextureBatchBit(maxTextures), + localUniformMSDFBit, + mSDFBit, + roundPixelsBit + ] + }); + glProgram$1 != null ? glProgram$1 : glProgram$1 = compileHighShaderGlProgram({ + name: "sdf-shader", + bits: [ + colorBitGl, + generateTextureBatchBitGl(maxTextures), + localUniformMSDFBitGl, + mSDFBitGl, + roundPixelsBitGl + ] + }); + super({ + glProgram: glProgram$1, + gpuProgram: gpuProgram$1, + resources: { + localUniforms: uniforms, + batchSamplers: getBatchSamplersUniformGroup(maxTextures) + } + }); + } + } + + "use strict"; + class AbstractBitmapFont extends EventEmitter { + constructor() { + super(...arguments); + /** The map of characters by character code. */ + this.chars = /* @__PURE__ */ Object.create(null); + /** + * The line-height of the font face in pixels. + * @type {number} + */ + this.lineHeight = 0; + /** + * The name of the font face + * @type {string} + */ + this.fontFamily = ""; + /** The metrics of the font face. */ + this.fontMetrics = { fontSize: 0, ascent: 0, descent: 0 }; + /** + * The offset of the font face from the baseline. + * @type {number} + */ + this.baseLineOffset = 0; + /** The range and type of the distance field for this font. */ + this.distanceField = { type: "none", range: 0 }; + /** The map of base page textures (i.e., sheets of glyphs). */ + this.pages = []; + /** The size of the font face in pixels. */ + this.baseMeasurementFontSize = 100; + this.baseRenderedFontSize = 100; + } + /** + * The name of the font face. + * @deprecated since 8.0.0 Use `fontFamily` instead. + */ + get font() { + deprecation(v8_0_0, "BitmapFont.font is deprecated, please use BitmapFont.fontFamily instead."); + return this.fontFamily; + } + /** + * The map of base page textures (i.e., sheets of glyphs). + * @deprecated since 8.0.0 Use `pages` instead. + */ + get pageTextures() { + deprecation(v8_0_0, "BitmapFont.pageTextures is deprecated, please use BitmapFont.pages instead."); + return this.pages; + } + /** + * The size of the font face in pixels. + * @deprecated since 8.0.0 Use `fontMetrics.fontSize` instead. + */ + get size() { + deprecation(v8_0_0, "BitmapFont.size is deprecated, please use BitmapFont.fontMetrics.fontSize instead."); + return this.fontMetrics.fontSize; + } + /** + * The kind of distance field for this font or "none". + * @deprecated since 8.0.0 Use `distanceField.type` instead. + */ + get distanceFieldRange() { + deprecation(v8_0_0, "BitmapFont.distanceFieldRange is deprecated, please use BitmapFont.distanceField.range instead."); + return this.distanceField.range; + } + /** + * The range of the distance field in pixels. + * @deprecated since 8.0.0 Use `distanceField.range` instead. + */ + get distanceFieldType() { + deprecation(v8_0_0, "BitmapFont.distanceFieldType is deprecated, please use BitmapFont.distanceField.type instead."); + return this.distanceField.type; + } + destroy(destroyTextures = false) { + var _a; + this.emit("destroy", this); + this.removeAllListeners(); + for (const i in this.chars) { + (_a = this.chars[i].texture) == null ? void 0 : _a.destroy(); + } + this.chars = null; + if (destroyTextures) { + this.pages.forEach((page) => page.texture.destroy(true)); + this.pages = null; + } + } + } + + "use strict"; + function resolveCharacters(chars) { + if (chars === "") { + return []; + } + if (typeof chars === "string") { + chars = [chars]; + } + const result = []; + for (let i = 0, j = chars.length; i < j; i++) { + const item = chars[i]; + if (Array.isArray(item)) { + if (item.length !== 2) { + throw new Error(`[BitmapFont]: Invalid character range length, expecting 2 got ${item.length}.`); + } + if (item[0].length === 0 || item[1].length === 0) { + throw new Error("[BitmapFont]: Invalid character delimiter."); + } + const startCode = item[0].charCodeAt(0); + const endCode = item[1].charCodeAt(0); + if (endCode < startCode) { + throw new Error("[BitmapFont]: Invalid character range."); + } + for (let i2 = startCode, j2 = endCode; i2 <= j2; i2++) { + result.push(String.fromCharCode(i2)); + } + } else { + result.push(...Array.from(item)); + } + } + if (result.length === 0) { + throw new Error("[BitmapFont]: Empty set when resolving characters."); + } + return result; + } + + "use strict"; + class DynamicBitmapFont extends AbstractBitmapFont { + /** + * @param options - The options for the dynamic bitmap font. + */ + constructor(options) { + var _a, _b, _c; + super(); + /** + * this is a resolution modifier for the font size.. + * texture resolution will also be used to scale texture according to its font size also + */ + this.resolution = 1; + /** The pages of the font. */ + this.pages = []; + this._padding = 4; + this._measureCache = /* @__PURE__ */ Object.create(null); + this._currentChars = []; + this._currentX = 0; + this._currentY = 0; + this._currentPageIndex = -1; + this._skipKerning = false; + const dynamicOptions = options; + const style = dynamicOptions.style.clone(); + if (dynamicOptions.overrideFill) { + style._fill.color = 16777215; + style._fill.alpha = 1; + style._fill.texture = Texture.WHITE; + style._fill.fill = null; + } + const requestedFontSize = style.fontSize; + style.fontSize = this.baseMeasurementFontSize; + const font = fontStringFromTextStyle(style); + if (dynamicOptions.overrideSize) { + if (style._stroke) { + style._stroke.width *= this.baseRenderedFontSize / requestedFontSize; + } + } else { + style.fontSize = this.baseRenderedFontSize = requestedFontSize; + } + this._style = style; + this._skipKerning = (_a = dynamicOptions.skipKerning) != null ? _a : false; + this.resolution = (_b = dynamicOptions.resolution) != null ? _b : 1; + this._padding = (_c = dynamicOptions.padding) != null ? _c : 4; + this.fontMetrics = CanvasTextMetrics.measureFont(font); + this.lineHeight = style.lineHeight || this.fontMetrics.fontSize || style.fontSize; + } + ensureCharacters(chars) { + var _a, _b, _c, _d; + const charList = resolveCharacters(chars).filter((char) => !this._currentChars.includes(char)).filter((char, index, self) => self.indexOf(char) === index); + if (!charList.length) + return; + this._currentChars = [...this._currentChars, ...charList]; + let pageData; + if (this._currentPageIndex === -1) { + pageData = this._nextPage(); + } else { + pageData = this.pages[this._currentPageIndex]; + } + let { canvas, context } = pageData.canvasAndContext; + let textureSource = pageData.texture.source; + const style = this._style; + let currentX = this._currentX; + let currentY = this._currentY; + const fontScale = this.baseRenderedFontSize / this.baseMeasurementFontSize; + const padding = this._padding * fontScale; + const widthScale = style.fontStyle === "italic" ? 2 : 1; + let maxCharHeight = 0; + let skipTexture = false; + for (let i = 0; i < charList.length; i++) { + const char = charList[i]; + const metrics = CanvasTextMetrics.measureText(char, style, canvas, false); + metrics.lineHeight = metrics.height; + const width = widthScale * metrics.width * fontScale; + const height = metrics.height * fontScale; + const paddedWidth = width + padding * 2; + const paddedHeight = height + padding * 2; + skipTexture = false; + if (char !== "\n" && char !== "\r" && char !== " " && char !== " ") { + skipTexture = true; + maxCharHeight = Math.ceil(Math.max(paddedHeight, maxCharHeight)); + } + if (currentX + paddedWidth > 512) { + currentY += maxCharHeight; + maxCharHeight = paddedHeight; + currentX = 0; + if (currentY + maxCharHeight > 512) { + textureSource.update(); + const pageData2 = this._nextPage(); + canvas = pageData2.canvasAndContext.canvas; + context = pageData2.canvasAndContext.context; + textureSource = pageData2.texture.source; + currentY = 0; + } + } + const xAdvance = width / fontScale - ((_b = (_a = style.dropShadow) == null ? void 0 : _a.distance) != null ? _b : 0) - ((_d = (_c = style._stroke) == null ? void 0 : _c.width) != null ? _d : 0); + this.chars[char] = { + id: char.codePointAt(0), + xOffset: -this._padding, + yOffset: -this._padding, + xAdvance, + kerning: {} + }; + if (skipTexture) { + this._drawGlyph( + context, + metrics, + currentX + padding, + currentY + padding, + fontScale, + style + ); + const px = textureSource.width * fontScale; + const py = textureSource.height * fontScale; + const frame = new Rectangle( + currentX / px * textureSource.width, + currentY / py * textureSource.height, + paddedWidth / px * textureSource.width, + paddedHeight / py * textureSource.height + ); + this.chars[char].texture = new Texture({ + source: textureSource, + frame + }); + currentX += Math.ceil(paddedWidth); + } + } + textureSource.update(); + this._currentX = currentX; + this._currentY = currentY; + this._skipKerning && this._applyKerning(charList, context); + } + /** + * @deprecated since 8.0.0 + * The map of base page textures (i.e., sheets of glyphs). + */ + get pageTextures() { + deprecation(v8_0_0, "BitmapFont.pageTextures is deprecated, please use BitmapFont.pages instead."); + return this.pages; + } + _applyKerning(newChars, context) { + const measureCache = this._measureCache; + for (let i = 0; i < newChars.length; i++) { + const first = newChars[i]; + for (let j = 0; j < this._currentChars.length; j++) { + const second = this._currentChars[j]; + let c1 = measureCache[first]; + if (!c1) + c1 = measureCache[first] = context.measureText(first).width; + let c2 = measureCache[second]; + if (!c2) + c2 = measureCache[second] = context.measureText(second).width; + let total = context.measureText(first + second).width; + let amount = total - (c1 + c2); + if (amount) { + this.chars[first].kerning[second] = amount; + } + total = context.measureText(first + second).width; + amount = total - (c1 + c2); + if (amount) { + this.chars[second].kerning[first] = amount; + } + } + } + } + _nextPage() { + this._currentPageIndex++; + const textureResolution = this.resolution; + const canvasAndContext = CanvasPool.getOptimalCanvasAndContext(512, 512, textureResolution); + this._setupContext(canvasAndContext.context, this._style, textureResolution); + const resolution = textureResolution * (this.baseRenderedFontSize / this.baseMeasurementFontSize); + const texture = new Texture({ + source: new ImageSource({ + resource: canvasAndContext.canvas, + resolution, + alphaMode: "premultiply-alpha-on-upload" + }) + }); + const pageData = { + canvasAndContext, + texture + }; + this.pages[this._currentPageIndex] = pageData; + return pageData; + } + // canvas style! + _setupContext(context, style, resolution) { + var _a; + style.fontSize = this.baseRenderedFontSize; + context.scale(resolution, resolution); + context.font = fontStringFromTextStyle(style); + style.fontSize = this.baseMeasurementFontSize; + context.textBaseline = style.textBaseline; + const stroke = style._stroke; + const strokeThickness = (_a = stroke == null ? void 0 : stroke.width) != null ? _a : 0; + if (stroke) { + context.lineWidth = strokeThickness; + context.lineJoin = stroke.join; + context.miterLimit = stroke.miterLimit; + context.strokeStyle = getCanvasFillStyle(stroke, context); + } + if (style._fill) { + context.fillStyle = getCanvasFillStyle(style._fill, context); + } + if (style.dropShadow) { + const shadowOptions = style.dropShadow; + const rgb = Color.shared.setValue(shadowOptions.color).toArray(); + const dropShadowBlur = shadowOptions.blur * resolution; + const dropShadowDistance = shadowOptions.distance * resolution; + context.shadowColor = `rgba(${rgb[0] * 255},${rgb[1] * 255},${rgb[2] * 255},${shadowOptions.alpha})`; + context.shadowBlur = dropShadowBlur; + context.shadowOffsetX = Math.cos(shadowOptions.angle) * dropShadowDistance; + context.shadowOffsetY = Math.sin(shadowOptions.angle) * dropShadowDistance; + } else { + context.shadowColor = "black"; + context.shadowBlur = 0; + context.shadowOffsetX = 0; + context.shadowOffsetY = 0; + } + } + _drawGlyph(context, metrics, x, y, fontScale, style) { + var _a; + const char = metrics.text; + const fontProperties = metrics.fontProperties; + const stroke = style._stroke; + const strokeThickness = ((_a = stroke == null ? void 0 : stroke.width) != null ? _a : 0) * fontScale; + const tx = x + strokeThickness / 2; + const ty = y - strokeThickness / 2; + const descent = fontProperties.descent * fontScale; + const lineHeight = metrics.lineHeight * fontScale; + if (style.stroke && strokeThickness) { + context.strokeText(char, tx, ty + lineHeight - descent); + } + if (style._fill) { + context.fillText(char, tx, ty + lineHeight - descent); + } + } + destroy() { + super.destroy(); + for (let i = 0; i < this.pages.length; i++) { + const { canvasAndContext, texture } = this.pages[i]; + CanvasPool.returnCanvasAndContext(canvasAndContext); + texture.destroy(true); + } + this.pages = null; + } + } + + "use strict"; + function getBitmapTextLayout(chars, style, font) { + const layoutData = { + width: 0, + height: 0, + offsetY: 0, + scale: style.fontSize / font.baseMeasurementFontSize, + lines: [{ + width: 0, + charPositions: [], + spaceWidth: 0, + spacesIndex: [], + chars: [] + }] + }; + layoutData.offsetY = font.baseLineOffset; + let currentLine = layoutData.lines[0]; + let previousChar = null; + let firstWord = true; + const currentWord = { + spaceWord: false, + width: 0, + start: 0, + index: 0, + // use index to not modify the array as we use it a lot! + positions: [], + chars: [] + }; + const nextWord = (word) => { + const start = currentLine.width; + for (let j = 0; j < currentWord.index; j++) { + const position = word.positions[j]; + currentLine.chars.push(word.chars[j]); + currentLine.charPositions.push(position + start); + } + currentLine.width += word.width; + firstWord = false; + currentWord.width = 0; + currentWord.index = 0; + currentWord.chars.length = 0; + }; + const nextLine = () => { + let index = currentLine.chars.length - 1; + let lastChar = currentLine.chars[index]; + while (lastChar === " ") { + currentLine.width -= font.chars[lastChar].xAdvance; + lastChar = currentLine.chars[--index]; + } + layoutData.width = Math.max(layoutData.width, currentLine.width); + currentLine = { + width: 0, + charPositions: [], + chars: [], + spaceWidth: 0, + spacesIndex: [] + }; + firstWord = true; + layoutData.lines.push(currentLine); + layoutData.height += font.lineHeight; + }; + const scale = font.baseMeasurementFontSize / style.fontSize; + const adjustedLetterSpacing = style.letterSpacing * scale; + const adjustedWordWrapWidth = style.wordWrapWidth * scale; + for (let i = 0; i < chars.length + 1; i++) { + let char; + const isEnd = i === chars.length; + if (!isEnd) { + char = chars[i]; + } + const charData = font.chars[char] || font.chars[" "]; + const isSpace = /(?:\s)/.test(char); + const isWordBreak = isSpace || char === "\r" || char === "\n" || isEnd; + if (isWordBreak) { + const addWordToNextLine = !firstWord && style.wordWrap && currentLine.width + currentWord.width - adjustedLetterSpacing > adjustedWordWrapWidth; + if (addWordToNextLine) { + nextLine(); + nextWord(currentWord); + if (!isEnd) { + currentLine.charPositions.push(0); + } + } else { + currentWord.start = currentLine.width; + nextWord(currentWord); + if (!isEnd) { + currentLine.charPositions.push(0); + } + } + if (char === "\r" || char === "\n") { + if (currentLine.width !== 0) { + nextLine(); + } + } else if (!isEnd) { + const spaceWidth = charData.xAdvance + (charData.kerning[previousChar] || 0) + adjustedLetterSpacing; + currentLine.width += spaceWidth; + currentLine.spaceWidth = spaceWidth; + currentLine.spacesIndex.push(currentLine.charPositions.length); + currentLine.chars.push(char); + } + } else { + const kerning = charData.kerning[previousChar] || 0; + const nextCharWidth = charData.xAdvance + kerning + adjustedLetterSpacing; + currentWord.positions[currentWord.index++] = currentWord.width + kerning; + currentWord.chars.push(char); + currentWord.width += nextCharWidth; + } + previousChar = char; + } + nextLine(); + if (style.align === "center") { + alignCenter(layoutData); + } else if (style.align === "right") { + alignRight(layoutData); + } else if (style.align === "justify") { + alignJustify(layoutData); + } + return layoutData; + } + function alignCenter(measurementData) { + for (let i = 0; i < measurementData.lines.length; i++) { + const line = measurementData.lines[i]; + const offset = measurementData.width / 2 - line.width / 2; + for (let j = 0; j < line.charPositions.length; j++) { + line.charPositions[j] += offset; + } + } + } + function alignRight(measurementData) { + for (let i = 0; i < measurementData.lines.length; i++) { + const line = measurementData.lines[i]; + const offset = measurementData.width - line.width; + for (let j = 0; j < line.charPositions.length; j++) { + line.charPositions[j] += offset; + } + } + } + function alignJustify(measurementData) { + const width = measurementData.width; + for (let i = 0; i < measurementData.lines.length; i++) { + const line = measurementData.lines[i]; + let indy = 0; + let spaceIndex = line.spacesIndex[indy++]; + let offset = 0; + const totalSpaces = line.spacesIndex.length; + const newSpaceWidth = (width - line.width) / totalSpaces; + const spaceWidth = newSpaceWidth; + for (let j = 0; j < line.charPositions.length; j++) { + if (j === spaceIndex) { + spaceIndex = line.spacesIndex[indy++]; + offset += spaceWidth; + } + line.charPositions[j] += offset; + } + } + } + + "use strict"; + var __defProp$J = Object.defineProperty; + var __getOwnPropSymbols$J = Object.getOwnPropertySymbols; + var __hasOwnProp$J = Object.prototype.hasOwnProperty; + var __propIsEnum$J = Object.prototype.propertyIsEnumerable; + var __defNormalProp$J = (obj, key, value) => key in obj ? __defProp$J(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$J = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$J.call(b, prop)) + __defNormalProp$J(a, prop, b[prop]); + if (__getOwnPropSymbols$J) + for (var prop of __getOwnPropSymbols$J(b)) { + if (__propIsEnum$J.call(b, prop)) + __defNormalProp$J(a, prop, b[prop]); + } + return a; + }; + class BitmapFontManagerClass { + constructor() { + /** + * This character set includes all the letters in the alphabet (both lower- and upper- case). + * @type {string[][]} + * @example + * BitmapFont.from('ExampleFont', style, { chars: BitmapFont.ALPHA }) + */ + this.ALPHA = [["a", "z"], ["A", "Z"], " "]; + /** + * This character set includes all decimal digits (from 0 to 9). + * @type {string[][]} + * @example + * BitmapFont.from('ExampleFont', style, { chars: BitmapFont.NUMERIC }) + */ + this.NUMERIC = [["0", "9"]]; + /** + * This character set is the union of `BitmapFont.ALPHA` and `BitmapFont.NUMERIC`. + * @type {string[][]} + */ + this.ALPHANUMERIC = [["a", "z"], ["A", "Z"], ["0", "9"], " "]; + /** + * This character set consists of all the ASCII table. + * @member {string[][]} + * @see http://www.asciitable.com/ + */ + this.ASCII = [[" ", "~"]]; + /** Default options for installing a new BitmapFont. */ + this.defaultOptions = { + chars: this.ALPHANUMERIC, + resolution: 1, + padding: 4, + skipKerning: false + }; + } + /** + * Get a font for the specified text and style. + * @param text - The text to get the font for + * @param style - The style to use + */ + getFont(text, style) { + var _a; + let fontFamilyKey = `${style.fontFamily}-bitmap`; + let overrideFill = true; + if (style._fill.fill) { + fontFamilyKey += style._fill.fill.uid; + overrideFill = false; + } + if (!Cache.has(fontFamilyKey)) { + const fnt = new DynamicBitmapFont(__spreadValues$J({ + style, + overrideFill, + overrideSize: true + }, this.defaultOptions)); + fnt.once("destroy", () => Cache.remove(fontFamilyKey)); + Cache.set( + fontFamilyKey, + fnt + ); + } + const dynamicFont = Cache.get(fontFamilyKey); + (_a = dynamicFont.ensureCharacters) == null ? void 0 : _a.call(dynamicFont, text); + return dynamicFont; + } + /** + * Get the layout of a text for the specified style. + * @param text - The text to get the layout for + * @param style - The style to use + */ + getLayout(text, style) { + const bitmapFont = this.getFont(text, style); + return getBitmapTextLayout([...text], style, bitmapFont); + } + /** + * Measure the text using the specified style. + * @param text - The text to measure + * @param style - The style to use + */ + measureText(text, style) { + return this.getLayout(text, style); + } + // eslint-disable-next-line max-len + install(...args) { + var _a, _b, _c, _d; + let options = args[0]; + if (typeof options === "string") { + options = { + name: options, + style: args[1], + chars: (_a = args[2]) == null ? void 0 : _a.chars, + resolution: (_b = args[2]) == null ? void 0 : _b.resolution, + padding: (_c = args[2]) == null ? void 0 : _c.padding, + skipKerning: (_d = args[2]) == null ? void 0 : _d.skipKerning + }; + deprecation(v8_0_0, "BitmapFontManager.install(name, style, options) is deprecated, use BitmapFontManager.install({name, style, ...options})"); + } + const name = options == null ? void 0 : options.name; + if (!name) { + throw new Error("[BitmapFontManager] Property `name` is required."); + } + options = __spreadValues$J(__spreadValues$J({}, this.defaultOptions), options); + const textStyle = options.style; + const style = textStyle instanceof TextStyle ? textStyle : new TextStyle(textStyle); + const overrideFill = style._fill.fill !== null && style._fill.fill !== void 0; + const font = new DynamicBitmapFont({ + style, + overrideFill, + skipKerning: options.skipKerning, + padding: options.padding, + resolution: options.resolution, + overrideSize: false + }); + const flatChars = resolveCharacters(options.chars); + font.ensureCharacters(flatChars.join("")); + Cache.set(`${name}-bitmap`, font); + font.once("destroy", () => Cache.remove(`${name}-bitmap`)); + return font; + } + /** + * Uninstalls a bitmap font from the cache. + * @param {string} name - The name of the bitmap font to uninstall. + */ + uninstall(name) { + const cacheKey = `${name}-bitmap`; + const font = Cache.get(cacheKey); + if (font) { + Cache.remove(cacheKey); + font.destroy(); + } + } + } + const BitmapFontManager = new BitmapFontManagerClass(); + + "use strict"; + class BitmapTextPipe { + // private _sdfShader: SdfShader; + constructor(renderer) { + this._gpuBitmapText = {}; + this._renderer = renderer; + } + validateRenderable(bitmapText) { + const graphicsRenderable = this._getGpuBitmapText(bitmapText); + if (bitmapText._didTextUpdate) { + bitmapText._didTextUpdate = false; + this._updateContext(bitmapText, graphicsRenderable); + } + return this._renderer.renderPipes.graphics.validateRenderable(graphicsRenderable); + } + addRenderable(bitmapText, instructionSet) { + const graphicsRenderable = this._getGpuBitmapText(bitmapText); + syncWithProxy(bitmapText, graphicsRenderable); + if (bitmapText._didTextUpdate) { + bitmapText._didTextUpdate = false; + this._updateContext(bitmapText, graphicsRenderable); + } + this._renderer.renderPipes.graphics.addRenderable(graphicsRenderable, instructionSet); + if (graphicsRenderable.context.customShader) { + this._updateDistanceField(bitmapText); + } + } + destroyRenderable(bitmapText) { + this._destroyRenderableByUid(bitmapText.uid); + } + _destroyRenderableByUid(renderableUid) { + const context = this._gpuBitmapText[renderableUid].context; + if (context.customShader) { + BigPool.return(context.customShader); + context.customShader = null; + } + BigPool.return(this._gpuBitmapText[renderableUid]); + this._gpuBitmapText[renderableUid] = null; + } + updateRenderable(bitmapText) { + const graphicsRenderable = this._getGpuBitmapText(bitmapText); + syncWithProxy(bitmapText, graphicsRenderable); + this._renderer.renderPipes.graphics.updateRenderable(graphicsRenderable); + if (graphicsRenderable.context.customShader) { + this._updateDistanceField(bitmapText); + } + } + _updateContext(bitmapText, proxyGraphics) { + var _a; + const { context } = proxyGraphics; + const bitmapFont = BitmapFontManager.getFont(bitmapText.text, bitmapText._style); + context.clear(); + if (bitmapFont.distanceField.type !== "none") { + if (!context.customShader) { + context.customShader = BigPool.get(SdfShader); + } + } + const chars = Array.from(bitmapText.text); + const style = bitmapText._style; + let currentY = (((_a = style._stroke) == null ? void 0 : _a.width) || 0) / 2; + currentY += bitmapFont.baseLineOffset; + const bitmapTextLayout = getBitmapTextLayout(chars, style, bitmapFont); + let index = 0; + const padding = style.padding; + const scale = bitmapTextLayout.scale; + context.translate( + -bitmapText._anchor._x * bitmapTextLayout.width - padding, + -bitmapText._anchor._y * (bitmapTextLayout.height + bitmapTextLayout.offsetY) - padding + ).scale(scale, scale); + const tint = style._fill.color; + for (let i = 0; i < bitmapTextLayout.lines.length; i++) { + const line = bitmapTextLayout.lines[i]; + for (let j = 0; j < line.charPositions.length; j++) { + const char = chars[index++]; + const charData = bitmapFont.chars[char]; + if (charData == null ? void 0 : charData.texture) { + context.texture( + charData.texture, + tint ? tint : "black", + Math.round(line.charPositions[j] + charData.xOffset), + Math.round(currentY + charData.yOffset) + ); + } + } + currentY += bitmapFont.lineHeight; + } + } + _getGpuBitmapText(bitmapText) { + return this._gpuBitmapText[bitmapText.uid] || this.initGpuText(bitmapText); + } + initGpuText(bitmapText) { + const proxyRenderable = BigPool.get(Graphics); + this._gpuBitmapText[bitmapText.uid] = proxyRenderable; + this._updateContext(bitmapText, proxyRenderable); + bitmapText.on("destroyed", () => { + this.destroyRenderable(bitmapText); + }); + return this._gpuBitmapText[bitmapText.uid]; + } + _updateDistanceField(bitmapText) { + const context = this._getGpuBitmapText(bitmapText).context; + const fontFamily = bitmapText._style.fontFamily; + const dynamicFont = Cache.get(`${fontFamily}-bitmap`); + const { a, b, c, d } = bitmapText.groupTransform; + const dx = Math.sqrt(a * a + b * b); + const dy = Math.sqrt(c * c + d * d); + const worldScale = (Math.abs(dx) + Math.abs(dy)) / 2; + const fontScale = dynamicFont.baseRenderedFontSize / bitmapText._style.fontSize; + const distance = worldScale * dynamicFont.distanceField.range * (1 / fontScale); + context.customShader.resources.localUniforms.uniforms.uDistance = distance; + } + destroy() { + for (const uid in this._gpuBitmapText) { + this._destroyRenderableByUid(uid); + } + this._gpuBitmapText = null; + this._renderer = null; + } + } + /** @ignore */ + BitmapTextPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "bitmapText" + }; + function syncWithProxy(container, proxy) { + proxy.groupTransform = container.groupTransform; + proxy.groupColorAlpha = container.groupColorAlpha; + proxy.groupColor = container.groupColor; + proxy.groupBlendMode = container.groupBlendMode; + proxy.globalDisplayStatus = container.globalDisplayStatus; + proxy.groupTransform = container.groupTransform; + proxy.localDisplayStatus = container.localDisplayStatus; + proxy.groupAlpha = container.groupAlpha; + proxy._roundPixels = container._roundPixels; + } + + "use strict"; + extensions.add(BitmapTextPipe); + + "use strict"; + class HTMLTextPipe { + constructor(renderer) { + this._gpuText = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + validateRenderable(htmlText) { + const gpuText = this._getGpuText(htmlText); + const newKey = htmlText._getKey(); + if (gpuText.textureNeedsUploading) { + gpuText.textureNeedsUploading = false; + return true; + } + if (gpuText.currentKey !== newKey) { + return true; + } + return false; + } + addRenderable(htmlText) { + const gpuText = this._getGpuText(htmlText); + const batchableSprite = gpuText.batchableSprite; + if (htmlText._didTextUpdate) { + this._updateText(htmlText); + } + this._renderer.renderPipes.batch.addToBatch(batchableSprite); + } + updateRenderable(htmlText) { + const gpuText = this._getGpuText(htmlText); + const batchableSprite = gpuText.batchableSprite; + if (htmlText._didTextUpdate) { + this._updateText(htmlText); + } + batchableSprite.batcher.updateElement(batchableSprite); + } + destroyRenderable(htmlText) { + this._destroyRenderableById(htmlText.uid); + } + _destroyRenderableById(htmlTextUid) { + const gpuText = this._gpuText[htmlTextUid]; + this._renderer.htmlText.decreaseReferenceCount(gpuText.currentKey); + BigPool.return(gpuText.batchableSprite); + this._gpuText[htmlTextUid] = null; + } + _updateText(htmlText) { + const newKey = htmlText._getKey(); + const gpuText = this._getGpuText(htmlText); + const batchableSprite = gpuText.batchableSprite; + if (gpuText.currentKey !== newKey) { + this._updateGpuText(htmlText).catch((e) => { + console.error(e); + }); + } + htmlText._didTextUpdate = false; + const padding = htmlText._style.padding; + updateQuadBounds(batchableSprite.bounds, htmlText._anchor, batchableSprite.texture, padding); + } + async _updateGpuText(htmlText) { + var _a; + htmlText._didTextUpdate = false; + const gpuText = this._getGpuText(htmlText); + if (gpuText.generatingTexture) + return; + const newKey = htmlText._getKey(); + this._renderer.htmlText.decreaseReferenceCount(gpuText.currentKey); + gpuText.generatingTexture = true; + gpuText.currentKey = newKey; + const resolution = (_a = htmlText.resolution) != null ? _a : this._renderer.resolution; + const texture = await this._renderer.htmlText.getManagedTexture( + htmlText.text, + resolution, + htmlText._style, + htmlText._getKey() + ); + const batchableSprite = gpuText.batchableSprite; + batchableSprite.texture = gpuText.texture = texture; + gpuText.generatingTexture = false; + gpuText.textureNeedsUploading = true; + htmlText.onViewUpdate(); + const padding = htmlText._style.padding; + updateQuadBounds(batchableSprite.bounds, htmlText._anchor, batchableSprite.texture, padding); + } + _getGpuText(htmlText) { + return this._gpuText[htmlText.uid] || this.initGpuText(htmlText); + } + initGpuText(htmlText) { + const gpuTextData = { + texture: Texture.EMPTY, + currentKey: "--", + batchableSprite: BigPool.get(BatchableSprite), + textureNeedsUploading: false, + generatingTexture: false + }; + const batchableSprite = gpuTextData.batchableSprite; + batchableSprite.renderable = htmlText; + batchableSprite.texture = Texture.EMPTY; + batchableSprite.bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 }; + batchableSprite.roundPixels = this._renderer._roundPixels | htmlText._roundPixels; + this._gpuText[htmlText.uid] = gpuTextData; + htmlText.on("destroyed", () => { + this.destroyRenderable(htmlText); + }); + return gpuTextData; + } + destroy() { + for (const i in this._gpuText) { + this._destroyRenderableById(i); + } + this._gpuText = null; + this._renderer = null; + } + } + /** @ignore */ + HTMLTextPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "htmlText" + }; + + "use strict"; + function isSafari() { + const { userAgent } = DOMAdapter.get().getNavigator(); + return /^((?!chrome|android).)*safari/i.test(userAgent); + } + + "use strict"; + const nssvg = "http://www.w3.org/2000/svg"; + const nsxhtml = "http://www.w3.org/1999/xhtml"; + class HTMLTextRenderData { + constructor() { + this.svgRoot = document.createElementNS(nssvg, "svg"); + this.foreignObject = document.createElementNS(nssvg, "foreignObject"); + this.domElement = document.createElementNS(nsxhtml, "div"); + this.styleElement = document.createElementNS(nsxhtml, "style"); + this.image = new Image(); + const { foreignObject, svgRoot, styleElement, domElement } = this; + foreignObject.setAttribute("width", "10000"); + foreignObject.setAttribute("height", "10000"); + foreignObject.style.overflow = "hidden"; + svgRoot.appendChild(foreignObject); + foreignObject.appendChild(styleElement); + foreignObject.appendChild(domElement); + } + } + + "use strict"; + function textStyleToCSS(style) { + const stroke = style._stroke; + const fill = style._fill; + const cssStyleString = [ + `color: ${Color.shared.setValue(fill.color).toHex()}`, + `font-size: ${style.fontSize}px`, + `font-family: ${style.fontFamily}`, + `font-weight: ${style.fontWeight}`, + `font-style: ${style.fontStyle}`, + `font-variant: ${style.fontVariant}`, + `letter-spacing: ${style.letterSpacing}px`, + `text-align: ${style.align}`, + `padding: ${style.padding}px`, + `white-space: ${style.whiteSpace === "pre" && style.wordWrap ? "pre-wrap" : style.whiteSpace}`, + ...style.lineHeight ? [`line-height: ${style.lineHeight}px`] : [], + ...style.wordWrap ? [ + `word-wrap: ${style.breakWords ? "break-all" : "break-word"}`, + `max-width: ${style.wordWrapWidth}px` + ] : [], + ...stroke ? [strokeToCSS(stroke)] : [], + ...style.dropShadow ? [dropShadowToCSS(style.dropShadow)] : [], + ...style.cssOverrides + ].join(";"); + const cssStyles = [`div { ${cssStyleString} }`]; + tagStyleToCSS(style.tagStyles, cssStyles); + return cssStyles.join(" "); + } + function dropShadowToCSS(dropShadowStyle) { + const color = Color.shared.setValue(dropShadowStyle.color).setAlpha(dropShadowStyle.alpha).toHexa(); + const x = Math.round(Math.cos(dropShadowStyle.angle) * dropShadowStyle.distance); + const y = Math.round(Math.sin(dropShadowStyle.angle) * dropShadowStyle.distance); + const position = `${x}px ${y}px`; + if (dropShadowStyle.blur > 0) { + return `text-shadow: ${position} ${dropShadowStyle.blur}px ${color}`; + } + return `text-shadow: ${position} ${color}`; + } + function strokeToCSS(stroke) { + return [ + `-webkit-text-stroke-width: ${stroke.width}px`, + `-webkit-text-stroke-color: ${Color.shared.setValue(stroke.color).toHex()}`, + `text-stroke-width: ${stroke.width}px`, + `text-stroke-color: ${Color.shared.setValue(stroke.color).toHex()}`, + "paint-order: stroke" + ].join(";"); + } + const templates = { + fontSize: `font-size: {{VALUE}}px`, + fontFamily: `font-family: {{VALUE}}`, + fontWeight: `font-weight: {{VALUE}}`, + fontStyle: `font-style: {{VALUE}}`, + fontVariant: `font-variant: {{VALUE}}`, + letterSpacing: `letter-spacing: {{VALUE}}px`, + align: `text-align: {{VALUE}}`, + padding: `padding: {{VALUE}}px`, + whiteSpace: `white-space: {{VALUE}}`, + lineHeight: `line-height: {{VALUE}}px`, + wordWrapWidth: `max-width: {{VALUE}}px` + }; + const transform = { + fill: (value) => `color: ${Color.shared.setValue(value).toHex()}`, + breakWords: (value) => `word-wrap: ${value ? "break-all" : "break-word"}`, + stroke: strokeToCSS, + dropShadow: dropShadowToCSS + }; + function tagStyleToCSS(tagStyles, out) { + for (const i in tagStyles) { + const tagStyle = tagStyles[i]; + const cssTagStyle = []; + for (const j in tagStyle) { + if (transform[j]) { + cssTagStyle.push(transform[j](tagStyle[j])); + } else if (templates[j]) { + cssTagStyle.push(templates[j].replace("{{VALUE}}", tagStyle[j])); + } + } + out.push(`${i} { ${cssTagStyle.join(";")} }`); + } + } + + "use strict"; + var __defProp$I = Object.defineProperty; + var __getOwnPropSymbols$I = Object.getOwnPropertySymbols; + var __hasOwnProp$I = Object.prototype.hasOwnProperty; + var __propIsEnum$I = Object.prototype.propertyIsEnumerable; + var __defNormalProp$I = (obj, key, value) => key in obj ? __defProp$I(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$I = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$I.call(b, prop)) + __defNormalProp$I(a, prop, b[prop]); + if (__getOwnPropSymbols$I) + for (var prop of __getOwnPropSymbols$I(b)) { + if (__propIsEnum$I.call(b, prop)) + __defNormalProp$I(a, prop, b[prop]); + } + return a; + }; + class HTMLTextStyle extends TextStyle { + constructor(options = {}) { + var _a, _b; + super(options); + this._cssOverrides = []; + (_a = this.cssOverrides) != null ? _a : this.cssOverrides = options.cssOverrides; + this.tagStyles = (_b = options.tagStyles) != null ? _b : {}; + } + /** List of style overrides that will be applied to the HTML text. */ + set cssOverrides(value) { + this._cssOverrides = value instanceof Array ? value : [value]; + this.update(); + } + get cssOverrides() { + return this._cssOverrides; + } + _generateKey() { + this._styleKey = generateTextStyleKey(this) + this._cssOverrides.join("-"); + return this._styleKey; + } + update() { + this._cssStyle = null; + super.update(); + } + /** + * Creates a new HTMLTextStyle object with the same values as this one. + * @returns New cloned HTMLTextStyle object + */ + clone() { + return new HTMLTextStyle({ + align: this.align, + breakWords: this.breakWords, + dropShadow: this.dropShadow ? __spreadValues$I({}, this.dropShadow) : null, + fill: this._fill, + fontFamily: this.fontFamily, + fontSize: this.fontSize, + fontStyle: this.fontStyle, + fontVariant: this.fontVariant, + fontWeight: this.fontWeight, + letterSpacing: this.letterSpacing, + lineHeight: this.lineHeight, + padding: this.padding, + stroke: this._stroke, + whiteSpace: this.whiteSpace, + wordWrap: this.wordWrap, + wordWrapWidth: this.wordWrapWidth, + cssOverrides: this.cssOverrides + }); + } + get cssStyle() { + if (!this._cssStyle) { + this._cssStyle = textStyleToCSS(this); + } + return this._cssStyle; + } + /** + * Add a style override, this can be any CSS property + * it will override any built-in style. This is the + * property and the value as a string (e.g., `color: red`). + * This will override any other internal style. + * @param {string} value - CSS style(s) to add. + * @example + * style.addOverride('background-color: red'); + */ + addOverride(...value) { + const toAdd = value.filter((v) => !this.cssOverrides.includes(v)); + if (toAdd.length > 0) { + this.cssOverrides.push(...toAdd); + this.update(); + } + } + /** + * Remove any overrides that match the value. + * @param {string} value - CSS style to remove. + * @example + * style.removeOverride('background-color: red'); + */ + removeOverride(...value) { + const toRemove = value.filter((v) => this.cssOverrides.includes(v)); + if (toRemove.length > 0) { + this.cssOverrides = this.cssOverrides.filter((v) => !toRemove.includes(v)); + this.update(); + } + } + set fill(value) { + if (typeof value !== "string" && typeof value !== "number") { + warn("[HTMLTextStyle] only color fill is not supported by HTMLText"); + } + super.fill = value; + } + set stroke(value) { + if (value && typeof value !== "string" && typeof value !== "number") { + warn("[HTMLTextStyle] only color stroke is not supported by HTMLText"); + } + super.stroke = value; + } + } + + "use strict"; + function extractFontFamilies(text, style) { + const fontFamily = style.fontFamily; + const fontFamilies = []; + const dedupe = {}; + const regex = /font-family:([^;"\s]+)/g; + const matches = text.match(regex); + function addFontFamily(fontFamily2) { + if (!dedupe[fontFamily2]) { + fontFamilies.push(fontFamily2); + dedupe[fontFamily2] = true; + } + } + if (Array.isArray(fontFamily)) { + for (let i = 0; i < fontFamily.length; i++) { + addFontFamily(fontFamily[i]); + } + } else { + addFontFamily(fontFamily); + } + if (matches) { + matches.forEach((match) => { + const fontFamily2 = match.split(":")[1].trim(); + addFontFamily(fontFamily2); + }); + } + for (const i in style.tagStyles) { + const fontFamily2 = style.tagStyles[i].fontFamily; + addFontFamily(fontFamily2); + } + return fontFamilies; + } + + "use strict"; + async function loadFontAsBase64(url) { + const response = await DOMAdapter.get().fetch(url); + const blob = await response.blob(); + const reader = new FileReader(); + const dataSrc = await new Promise((resolve, reject) => { + reader.onloadend = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + return dataSrc; + } + + "use strict"; + async function loadFontCSS(style, url) { + const dataSrc = await loadFontAsBase64(url); + return `@font-face { + font-family: "${style.fontFamily}"; + src: url('${dataSrc}'); + font-weight: ${style.fontWeight}; + font-style: ${style.fontStyle}; + }`; + } + + "use strict"; + const FontStylePromiseCache = /* @__PURE__ */ new Map(); + async function getFontCss(fontFamilies, style, defaultOptions) { + const fontPromises = fontFamilies.filter((fontFamily) => Cache.has(`${fontFamily}-and-url`)).map((fontFamily, i) => { + if (!FontStylePromiseCache.has(fontFamily)) { + const { url } = Cache.get(`${fontFamily}-and-url`); + if (i === 0) { + FontStylePromiseCache.set(fontFamily, loadFontCSS(style, url)); + } else { + FontStylePromiseCache.set(fontFamily, loadFontCSS({ + fontWeight: defaultOptions.fontWeight, + fontStyle: defaultOptions.fontStyle, + fontFamily + }, url)); + } + } + return FontStylePromiseCache.get(fontFamily); + }); + return (await Promise.all(fontPromises)).join("\n"); + } + + "use strict"; + function getSVGUrl(text, style, resolution, fontCSS, htmlTextData) { + const { domElement, styleElement, svgRoot } = htmlTextData; + domElement.innerHTML = `
${text}
`; + domElement.setAttribute("style", `transform: scale(${resolution});transform-origin: top left; display: inline-block`); + styleElement.textContent = fontCSS; + const { width, height } = htmlTextData.image; + svgRoot.setAttribute("width", width.toString()); + svgRoot.setAttribute("height", height.toString()); + return new XMLSerializer().serializeToString(svgRoot); + } + + "use strict"; + function getTemporaryCanvasFromImage(image, resolution) { + const canvasAndContext = CanvasPool.getOptimalCanvasAndContext( + image.width, + image.height, + resolution + ); + const { context } = canvasAndContext; + context.clearRect(0, 0, image.width, image.height); + context.drawImage(image, 0, 0); + CanvasPool.returnCanvasAndContext(canvasAndContext); + return canvasAndContext.canvas; + } + + "use strict"; + function loadSVGImage(image, url, delay) { + return new Promise(async (resolve) => { + if (delay) { + await new Promise((resolve2) => setTimeout(resolve2, 100)); + } + image.onload = () => { + resolve(); + }; + image.src = `data:image/svg+xml;charset=utf8,${encodeURIComponent(url)}`; + image.crossOrigin = "anonymous"; + }); + } + + "use strict"; + let tempHTMLTextRenderData; + function measureHtmlText(text, style, fontStyleCSS, htmlTextRenderData) { + htmlTextRenderData = htmlTextRenderData || tempHTMLTextRenderData || (tempHTMLTextRenderData = new HTMLTextRenderData()); + const { domElement, styleElement, svgRoot } = htmlTextRenderData; + domElement.innerHTML = `
${text}
`; + domElement.setAttribute("style", "transform-origin: top left; display: inline-block"); + if (fontStyleCSS) { + styleElement.textContent = fontStyleCSS; + } + document.body.appendChild(svgRoot); + const contentBounds = domElement.getBoundingClientRect(); + svgRoot.remove(); + const descenderPadding = CanvasTextMetrics.measureFont(style.fontStyle).descent; + return { + width: contentBounds.width, + height: contentBounds.height + descenderPadding + }; + } + + "use strict"; + class HTMLTextSystem { + constructor(renderer) { + this._activeTextures = {}; + this._renderer = renderer; + this._createCanvas = renderer.type === RendererType.WEBGPU; + } + getTexture(options) { + return this._buildTexturePromise( + options.text, + options.resolution, + options.style + ); + } + getManagedTexture(text, resolution, style, textKey) { + if (this._activeTextures[textKey]) { + this._increaseReferenceCount(textKey); + return this._activeTextures[textKey].promise; + } + const promise = this._buildTexturePromise(text, resolution, style).then((texture) => { + this._activeTextures[textKey].texture = texture; + return texture; + }); + this._activeTextures[textKey] = { + texture: null, + promise, + usageCount: 1 + }; + return promise; + } + async _buildTexturePromise(text, resolution, style) { + const htmlTextData = BigPool.get(HTMLTextRenderData); + const fontFamilies = extractFontFamilies(text, style); + const fontCSS = await getFontCss( + fontFamilies, + style, + HTMLTextStyle.defaultTextStyle + ); + const measured = measureHtmlText(text, style, fontCSS, htmlTextData); + const width = Math.ceil(Math.ceil(Math.max(1, measured.width) + style.padding * 2) * resolution); + const height = Math.ceil(Math.ceil(Math.max(1, measured.height) + style.padding * 2) * resolution); + const image = htmlTextData.image; + image.width = width | 0; + image.height = height | 0; + const svgURL = getSVGUrl(text, style, resolution, fontCSS, htmlTextData); + await loadSVGImage(image, svgURL, isSafari() && fontFamilies.length > 0); + let resource = image; + if (this._createCanvas) { + resource = getTemporaryCanvasFromImage(image, resolution); + } + const texture = getPo2TextureFromSource(resource, image.width, image.height, resolution); + if (this._createCanvas) { + this._renderer.texture.initSource(texture.source); + } + BigPool.return(htmlTextData); + return texture; + } + _increaseReferenceCount(textKey) { + this._activeTextures[textKey].usageCount++; + } + decreaseReferenceCount(textKey) { + const activeTexture = this._activeTextures[textKey]; + if (!activeTexture) + return; + activeTexture.usageCount--; + if (activeTexture.usageCount === 0) { + if (activeTexture.texture) { + this._cleanUp(activeTexture); + } else { + activeTexture.promise.then((texture) => { + activeTexture.texture = texture; + this._cleanUp(activeTexture); + }).catch(() => { + warn("HTMLTextSystem: Failed to clean texture"); + }); + } + this._activeTextures[textKey] = null; + } + } + _cleanUp(activeTexture) { + TexturePool.returnTexture(activeTexture.texture); + activeTexture.texture.source.resource = null; + activeTexture.texture.source.uploadMethodId = "unknown"; + } + getReferenceCount(textKey) { + return this._activeTextures[textKey].usageCount; + } + destroy() { + this._activeTextures = null; + } + } + /** @ignore */ + HTMLTextSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "htmlText" + }; + HTMLTextSystem.defaultFontOptions = { + fontFamily: "Arial", + fontStyle: "normal", + fontWeight: "normal" + }; + + "use strict"; + extensions.add(HTMLTextSystem); + extensions.add(HTMLTextPipe); + + "use strict"; + var __defProp$H = Object.defineProperty; + var __getOwnPropSymbols$H = Object.getOwnPropertySymbols; + var __hasOwnProp$H = Object.prototype.hasOwnProperty; + var __propIsEnum$H = Object.prototype.propertyIsEnumerable; + var __defNormalProp$H = (obj, key, value) => key in obj ? __defProp$H(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$H = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$H.call(b, prop)) + __defNormalProp$H(a, prop, b[prop]); + if (__getOwnPropSymbols$H) + for (var prop of __getOwnPropSymbols$H(b)) { + if (__propIsEnum$H.call(b, prop)) + __defNormalProp$H(a, prop, b[prop]); + } + return a; + }; + const _MeshGeometry = class _MeshGeometry extends Geometry { + constructor(...args) { + var _a; + let options = (_a = args[0]) != null ? _a : {}; + if (options instanceof Float32Array) { + deprecation(v8_0_0, "use new MeshGeometry({ positions, uvs, indices }) instead"); + options = { + positions: options, + uvs: args[1], + indices: args[2] + }; + } + options = __spreadValues$H(__spreadValues$H({}, _MeshGeometry.defaultOptions), options); + const positions = options.positions || new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]); + const uvs = options.uvs || new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]); + const indices = options.indices || new Uint32Array([0, 1, 2, 0, 2, 3]); + const shrinkToFit = options.shrinkBuffersToFit; + const positionBuffer = new Buffer({ + data: positions, + label: "attribute-mesh-positions", + shrinkToFit, + usage: BufferUsage.VERTEX | BufferUsage.COPY_DST + }); + const uvBuffer = new Buffer({ + data: uvs, + label: "attribute-mesh-uvs", + shrinkToFit, + usage: BufferUsage.VERTEX | BufferUsage.COPY_DST + }); + const indexBuffer = new Buffer({ + data: indices, + label: "index-mesh-buffer", + shrinkToFit, + usage: BufferUsage.INDEX | BufferUsage.COPY_DST + }); + super({ + attributes: { + aPosition: { + buffer: positionBuffer, + format: "float32x2", + stride: 2 * 4, + offset: 0 + }, + aUV: { + buffer: uvBuffer, + format: "float32x2", + stride: 2 * 4, + offset: 0 + } + }, + indexBuffer, + topology: options.topology + }); + this.batchMode = "auto"; + } + /** The positions of the mesh. */ + get positions() { + return this.attributes.aPosition.buffer.data; + } + set positions(value) { + this.attributes.aPosition.buffer.data = value; + } + /** The UVs of the mesh. */ + get uvs() { + return this.attributes.aUV.buffer.data; + } + set uvs(value) { + this.attributes.aUV.buffer.data = value; + } + /** The indices of the mesh. */ + get indices() { + return this.indexBuffer.data; + } + set indices(value) { + this.indexBuffer.data = value; + } + }; + _MeshGeometry.defaultOptions = { + topology: "triangle-list", + shrinkBuffersToFit: false + }; + let MeshGeometry = _MeshGeometry; + + "use strict"; + var __defProp$G = Object.defineProperty; + var __defProps$i = Object.defineProperties; + var __getOwnPropDescs$i = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$G = Object.getOwnPropertySymbols; + var __hasOwnProp$G = Object.prototype.hasOwnProperty; + var __propIsEnum$G = Object.prototype.propertyIsEnumerable; + var __defNormalProp$G = (obj, key, value) => key in obj ? __defProp$G(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$G = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$G.call(b, prop)) + __defNormalProp$G(a, prop, b[prop]); + if (__getOwnPropSymbols$G) + for (var prop of __getOwnPropSymbols$G(b)) { + if (__propIsEnum$G.call(b, prop)) + __defNormalProp$G(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$i = (a, b) => __defProps$i(a, __getOwnPropDescs$i(b)); + const localUniformBit = { + name: "local-uniform-bit", + vertex: { + header: ( + /* wgsl */ + ` + + struct LocalUniforms { + uTransformMatrix:mat3x3, + uColor:vec4, + uRound:f32, + } + + @group(1) @binding(0) var localUniforms : LocalUniforms; + ` + ), + main: ( + /* wgsl */ + ` + vColor *= localUniforms.uColor; + modelMatrix *= localUniforms.uTransformMatrix; + ` + ), + end: ( + /* wgsl */ + ` + if(localUniforms.uRound == 1) + { + vPosition = vec4(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw); + } + ` + ) + } + }; + const localUniformBitGroup2 = __spreadProps$i(__spreadValues$G({}, localUniformBit), { + vertex: __spreadProps$i(__spreadValues$G({}, localUniformBit.vertex), { + // replace the group! + header: localUniformBit.vertex.header.replace("group(1)", "group(2)") + }) + }); + const localUniformBitGl = { + name: "local-uniform-bit", + vertex: { + header: ( + /* glsl */ + ` + + uniform mat3 uTransformMatrix; + uniform vec4 uColor; + uniform float uRound; + ` + ), + main: ( + /* glsl */ + ` + vColor *= uColor; + modelMatrix = uTransformMatrix; + ` + ), + end: ( + /* glsl */ + ` + if(uRound == 1.) + { + gl_Position.xy = roundPixels(gl_Position.xy, uResolution); + } + ` + ) + } + }; + + "use strict"; + const tilingBit = { + name: "tiling-bit", + vertex: { + header: ( + /* wgsl */ + ` + struct TilingUniforms { + uMapCoord:mat3x3, + uClampFrame:vec4, + uClampOffset:vec2, + uTextureTransform:mat3x3, + uSizeAnchor:vec4 + }; + + @group(2) @binding(0) var tilingUniforms: TilingUniforms; + @group(2) @binding(1) var uTexture: texture_2d; + @group(2) @binding(2) var uSampler: sampler; + ` + ), + main: ( + /* wgsl */ + ` + uv = (tilingUniforms.uTextureTransform * vec3(uv, 1.0)).xy; + + position = (position - tilingUniforms.uSizeAnchor.zw) * tilingUniforms.uSizeAnchor.xy; + ` + ) + }, + fragment: { + header: ( + /* wgsl */ + ` + struct TilingUniforms { + uMapCoord:mat3x3, + uClampFrame:vec4, + uClampOffset:vec2, + uTextureTransform:mat3x3, + uSizeAnchor:vec4 + }; + + @group(2) @binding(0) var tilingUniforms: TilingUniforms; + @group(2) @binding(1) var uTexture: texture_2d; + @group(2) @binding(2) var uSampler: sampler; + ` + ), + main: ( + /* wgsl */ + ` + + var coord = vUV + ceil(tilingUniforms.uClampOffset - vUV); + coord = (tilingUniforms.uMapCoord * vec3(coord, 1.0)).xy; + var unclamped = coord; + coord = clamp(coord, tilingUniforms.uClampFrame.xy, tilingUniforms.uClampFrame.zw); + + var bias = 0.; + + if(unclamped.x == coord.x && unclamped.y == coord.y) + { + bias = -32.; + } + + outColor = textureSampleBias(uTexture, uSampler, coord, bias); + ` + ) + } + }; + const tilingBitGl = { + name: "tiling-bit", + vertex: { + header: ( + /* glsl */ + ` + uniform mat3 uTextureTransform; + uniform vec4 uSizeAnchor; + + ` + ), + main: ( + /* glsl */ + ` + uv = (uTextureTransform * vec3(aUV, 1.0)).xy; + + position = (position - uSizeAnchor.zw) * uSizeAnchor.xy; + ` + ) + }, + fragment: { + header: ( + /* glsl */ + ` + uniform sampler2D uTexture; + uniform mat3 uMapCoord; + uniform vec4 uClampFrame; + uniform vec2 uClampOffset; + ` + ), + main: ( + /* glsl */ + ` + + vec2 coord = vUV + ceil(uClampOffset - vUV); + coord = (uMapCoord * vec3(coord, 1.0)).xy; + vec2 unclamped = coord; + coord = clamp(coord, uClampFrame.xy, uClampFrame.zw); + + outColor = texture(uTexture, coord, unclamped == coord ? 0.0 : -32.0);// lod-bias very negative to force lod 0 + + ` + ) + } + }; + + "use strict"; + let gpuProgram; + let glProgram; + class TilingSpriteShader extends Shader { + constructor() { + gpuProgram != null ? gpuProgram : gpuProgram = compileHighShaderGpuProgram({ + name: "tiling-sprite-shader", + bits: [ + localUniformBit, + tilingBit, + roundPixelsBit + ] + }); + glProgram != null ? glProgram : glProgram = compileHighShaderGlProgram({ + name: "tiling-sprite-shader", + bits: [ + localUniformBitGl, + tilingBitGl, + roundPixelsBitGl + ] + }); + const tilingUniforms = new UniformGroup({ + uMapCoord: { value: new Matrix(), type: "mat3x3" }, + uClampFrame: { value: new Float32Array([0, 0, 1, 1]), type: "vec4" }, + uClampOffset: { value: new Float32Array([0, 0]), type: "vec2" }, + uTextureTransform: { value: new Matrix(), type: "mat3x3" }, + uSizeAnchor: { value: new Float32Array([100, 100, 0.5, 0.5]), type: "vec4" } + }); + super({ + glProgram, + gpuProgram, + resources: { + localUniforms: new UniformGroup({ + uTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4" }, + uRound: { value: 0, type: "f32" } + }), + tilingUniforms, + uTexture: Texture.EMPTY.source, + uSampler: Texture.EMPTY.source.style + } + }); + } + updateUniforms(width, height, matrix, anchorX, anchorY, texture) { + const tilingUniforms = this.resources.tilingUniforms; + const textureWidth = texture.width; + const textureHeight = texture.height; + const textureMatrix = texture.textureMatrix; + const uTextureTransform = tilingUniforms.uniforms.uTextureTransform; + uTextureTransform.set( + matrix.a * textureWidth / width, + matrix.b * textureWidth / height, + matrix.c * textureHeight / width, + matrix.d * textureHeight / height, + matrix.tx / width, + matrix.ty / height + ); + uTextureTransform.invert(); + tilingUniforms.uniforms.uMapCoord = textureMatrix.mapCoord; + tilingUniforms.uniforms.uClampFrame = textureMatrix.uClampFrame; + tilingUniforms.uniforms.uClampOffset = textureMatrix.uClampOffset; + tilingUniforms.uniforms.uTextureTransform = uTextureTransform; + tilingUniforms.uniforms.uSizeAnchor[0] = width; + tilingUniforms.uniforms.uSizeAnchor[1] = height; + tilingUniforms.uniforms.uSizeAnchor[2] = anchorX; + tilingUniforms.uniforms.uSizeAnchor[3] = anchorY; + if (texture) { + this.resources.uTexture = texture.source; + this.resources.uSampler = texture.source.style; + } + } + } + + "use strict"; + class QuadGeometry extends MeshGeometry { + constructor() { + super({ + positions: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), + uvs: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), + indices: new Uint32Array([0, 1, 2, 0, 2, 3]) + }); + } + } + + "use strict"; + function setPositions(tilingSprite, positions) { + const anchorX = tilingSprite.anchor.x; + const anchorY = tilingSprite.anchor.y; + positions[0] = -anchorX * tilingSprite.width; + positions[1] = -anchorY * tilingSprite.height; + positions[2] = (1 - anchorX) * tilingSprite.width; + positions[3] = -anchorY * tilingSprite.height; + positions[4] = (1 - anchorX) * tilingSprite.width; + positions[5] = (1 - anchorY) * tilingSprite.height; + positions[6] = -anchorX * tilingSprite.width; + positions[7] = (1 - anchorY) * tilingSprite.height; + } + + "use strict"; + function applyMatrix(array, stride, offset, matrix) { + let index = 0; + const size = array.length / (stride || 2); + const a = matrix.a; + const b = matrix.b; + const c = matrix.c; + const d = matrix.d; + const tx = matrix.tx; + const ty = matrix.ty; + offset *= stride; + while (index < size) { + const x = array[offset]; + const y = array[offset + 1]; + array[offset] = a * x + c * y + tx; + array[offset + 1] = b * x + d * y + ty; + offset += stride; + index++; + } + } + + "use strict"; + function setUvs(tilingSprite, uvs) { + const texture = tilingSprite.texture; + const width = texture.frame.width; + const height = texture.frame.height; + let anchorX = 0; + let anchorY = 0; + if (tilingSprite._applyAnchorToTexture) { + anchorX = tilingSprite.anchor.x; + anchorY = tilingSprite.anchor.y; + } + uvs[0] = uvs[6] = -anchorX; + uvs[2] = uvs[4] = 1 - anchorX; + uvs[1] = uvs[3] = -anchorY; + uvs[5] = uvs[7] = 1 - anchorY; + const textureMatrix = Matrix.shared; + textureMatrix.copyFrom(tilingSprite._tileTransform.matrix); + textureMatrix.tx /= tilingSprite.width; + textureMatrix.ty /= tilingSprite.height; + textureMatrix.invert(); + textureMatrix.scale(tilingSprite.width / width, tilingSprite.height / height); + applyMatrix(uvs, 2, 0, textureMatrix); + } + + "use strict"; + const sharedQuad = new QuadGeometry(); + class TilingSpritePipe { + constructor(renderer) { + this._tilingSpriteDataHash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + validateRenderable(renderable) { + const tilingSpriteData = this._getTilingSpriteData(renderable); + const couldBatch = tilingSpriteData.canBatch; + this._updateCanBatch(renderable); + const canBatch = tilingSpriteData.canBatch; + if (canBatch && canBatch === couldBatch) { + const { batchableMesh } = tilingSpriteData; + if (batchableMesh.texture._source !== renderable.texture._source) { + return !batchableMesh.batcher.checkAndUpdateTexture(batchableMesh, renderable.texture); + } + } + return couldBatch !== canBatch; + } + addRenderable(tilingSprite, instructionSet) { + const batcher = this._renderer.renderPipes.batch; + this._updateCanBatch(tilingSprite); + const tilingSpriteData = this._getTilingSpriteData(tilingSprite); + const { geometry, canBatch } = tilingSpriteData; + if (canBatch) { + tilingSpriteData.batchableMesh || (tilingSpriteData.batchableMesh = new BatchableMesh()); + const batchableMesh = tilingSpriteData.batchableMesh; + if (tilingSprite._didTilingSpriteUpdate) { + tilingSprite._didTilingSpriteUpdate = false; + this._updateBatchableMesh(tilingSprite); + batchableMesh.geometry = geometry; + batchableMesh.mesh = tilingSprite; + batchableMesh.texture = tilingSprite._texture; + } + batchableMesh.roundPixels = this._renderer._roundPixels | tilingSprite._roundPixels; + batcher.addToBatch(batchableMesh); + } else { + batcher.break(instructionSet); + tilingSpriteData.shader || (tilingSpriteData.shader = new TilingSpriteShader()); + this.updateRenderable(tilingSprite); + instructionSet.add(tilingSprite); + } + } + execute(tilingSprite) { + const { shader } = this._tilingSpriteDataHash[tilingSprite.uid]; + shader.groups[0] = this._renderer.globalUniforms.bindGroup; + const localUniforms = shader.resources.localUniforms.uniforms; + localUniforms.uTransformMatrix = tilingSprite.groupTransform; + localUniforms.uRound = this._renderer._roundPixels | tilingSprite._roundPixels; + color32BitToUniform( + tilingSprite.groupColorAlpha, + localUniforms.uColor, + 0 + ); + this._renderer.encoder.draw({ + geometry: sharedQuad, + shader, + state: State.default2d + }); + } + updateRenderable(tilingSprite) { + const tilingSpriteData = this._getTilingSpriteData(tilingSprite); + const { canBatch } = tilingSpriteData; + if (canBatch) { + const { batchableMesh } = tilingSpriteData; + if (tilingSprite._didTilingSpriteUpdate) + this._updateBatchableMesh(tilingSprite); + batchableMesh.batcher.updateElement(batchableMesh); + } else if (tilingSprite._didTilingSpriteUpdate) { + const { shader } = tilingSpriteData; + shader.updateUniforms( + tilingSprite.width, + tilingSprite.height, + tilingSprite._tileTransform.matrix, + tilingSprite.anchor.x, + tilingSprite.anchor.y, + tilingSprite.texture + ); + } + tilingSprite._didTilingSpriteUpdate = false; + } + destroyRenderable(tilingSprite) { + var _a; + const tilingSpriteData = this._getTilingSpriteData(tilingSprite); + tilingSpriteData.batchableMesh = null; + (_a = tilingSpriteData.shader) == null ? void 0 : _a.destroy(); + this._tilingSpriteDataHash[tilingSprite.uid] = null; + } + _getTilingSpriteData(renderable) { + return this._tilingSpriteDataHash[renderable.uid] || this._initTilingSpriteData(renderable); + } + _initTilingSpriteData(tilingSprite) { + const geometry = new MeshGeometry({ + indices: sharedQuad.indices, + positions: sharedQuad.positions.slice(), + uvs: sharedQuad.uvs.slice() + }); + this._tilingSpriteDataHash[tilingSprite.uid] = { + canBatch: true, + renderable: tilingSprite, + geometry + }; + tilingSprite.on("destroyed", () => { + this.destroyRenderable(tilingSprite); + }); + return this._tilingSpriteDataHash[tilingSprite.uid]; + } + _updateBatchableMesh(tilingSprite) { + const renderableData = this._getTilingSpriteData(tilingSprite); + const { geometry } = renderableData; + const style = tilingSprite.texture.source.style; + if (style.addressMode !== "repeat") { + style.addressMode = "repeat"; + style.update(); + } + setUvs(tilingSprite, geometry.uvs); + setPositions(tilingSprite, geometry.positions); + } + destroy() { + for (const i in this._tilingSpriteDataHash) { + this.destroyRenderable(this._tilingSpriteDataHash[i].renderable); + } + this._tilingSpriteDataHash = null; + this._renderer = null; + } + _updateCanBatch(tilingSprite) { + const renderableData = this._getTilingSpriteData(tilingSprite); + const texture = tilingSprite.texture; + let _nonPowOf2wrapping = true; + if (this._renderer.type === RendererType.WEBGL) { + _nonPowOf2wrapping = this._renderer.context.supports.nonPowOf2wrapping; + } + renderableData.canBatch = texture.textureMatrix.isSimple && (_nonPowOf2wrapping || texture.source.isPowerOfTwo); + return renderableData.canBatch; + } + } + /** @ignore */ + TilingSpritePipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "tilingSprite" + }; + + "use strict"; + extensions.add(TilingSpritePipe); + + "use strict"; + var __defProp$F = Object.defineProperty; + var __getOwnPropSymbols$F = Object.getOwnPropertySymbols; + var __hasOwnProp$F = Object.prototype.hasOwnProperty; + var __propIsEnum$F = Object.prototype.propertyIsEnumerable; + var __defNormalProp$F = (obj, key, value) => key in obj ? __defProp$F(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$F = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$F.call(b, prop)) + __defNormalProp$F(a, prop, b[prop]); + if (__getOwnPropSymbols$F) + for (var prop of __getOwnPropSymbols$F(b)) { + if (__propIsEnum$F.call(b, prop)) + __defNormalProp$F(a, prop, b[prop]); + } + return a; + }; + const _PlaneGeometry = class _PlaneGeometry extends MeshGeometry { + constructor(...args) { + var _a; + super({}); + let options = (_a = args[0]) != null ? _a : {}; + if (typeof options === "number") { + deprecation(v8_0_0, "PlaneGeometry constructor changed please use { width, height, verticesX, verticesY } instead"); + options = { + width: options, + height: args[1], + verticesX: args[2], + verticesY: args[3] + }; + } + this.build(options); + } + /** + * Refreshes plane coordinates + * @param options - Options to be applied to plane geometry + */ + build(options) { + var _a, _b, _c, _d; + options = __spreadValues$F(__spreadValues$F({}, _PlaneGeometry.defaultOptions), options); + this.verticesX = (_a = this.verticesX) != null ? _a : options.verticesX; + this.verticesY = (_b = this.verticesY) != null ? _b : options.verticesY; + this.width = (_c = this.width) != null ? _c : options.width; + this.height = (_d = this.height) != null ? _d : options.height; + const total = this.verticesX * this.verticesY; + const verts = []; + const uvs = []; + const indices = []; + const verticesX = this.verticesX - 1; + const verticesY = this.verticesY - 1; + const sizeX = this.width / verticesX; + const sizeY = this.height / verticesY; + for (let i = 0; i < total; i++) { + const x = i % this.verticesX; + const y = i / this.verticesX | 0; + verts.push(x * sizeX, y * sizeY); + uvs.push(x / verticesX, y / verticesY); + } + const totalSub = verticesX * verticesY; + for (let i = 0; i < totalSub; i++) { + const xpos = i % verticesX; + const ypos = i / verticesX | 0; + const value = ypos * this.verticesX + xpos; + const value2 = ypos * this.verticesX + xpos + 1; + const value3 = (ypos + 1) * this.verticesX + xpos; + const value4 = (ypos + 1) * this.verticesX + xpos + 1; + indices.push( + value, + value2, + value3, + value2, + value4, + value3 + ); + } + this.buffers[0].data = new Float32Array(verts); + this.buffers[1].data = new Float32Array(uvs); + this.indexBuffer.data = new Uint32Array(indices); + this.buffers[0].update(); + this.buffers[1].update(); + this.indexBuffer.update(); + } + }; + _PlaneGeometry.defaultOptions = { + width: 100, + height: 100, + verticesX: 10, + verticesY: 10 + }; + let PlaneGeometry = _PlaneGeometry; + + "use strict"; + var __defProp$E = Object.defineProperty; + var __getOwnPropSymbols$E = Object.getOwnPropertySymbols; + var __hasOwnProp$E = Object.prototype.hasOwnProperty; + var __propIsEnum$E = Object.prototype.propertyIsEnumerable; + var __defNormalProp$E = (obj, key, value) => key in obj ? __defProp$E(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$E = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$E.call(b, prop)) + __defNormalProp$E(a, prop, b[prop]); + if (__getOwnPropSymbols$E) + for (var prop of __getOwnPropSymbols$E(b)) { + if (__propIsEnum$E.call(b, prop)) + __defNormalProp$E(a, prop, b[prop]); + } + return a; + }; + const _NineSliceGeometry = class _NineSliceGeometry extends PlaneGeometry { + constructor(options = {}) { + options = __spreadValues$E(__spreadValues$E({}, _NineSliceGeometry.defaultOptions), options); + super({ + width: options.width, + height: options.height, + verticesX: 4, + verticesY: 4 + }); + this.update(options); + } + /** + * Updates the NineSliceGeometry with the options. + * @param options - The options of the NineSliceGeometry. + */ + update(options) { + var _a, _b, _c, _d, _e, _f, _g, _h; + this.width = (_a = options.width) != null ? _a : this.width; + this.height = (_b = options.height) != null ? _b : this.height; + this._originalWidth = (_c = options.originalWidth) != null ? _c : this._originalWidth; + this._originalHeight = (_d = options.originalHeight) != null ? _d : this._originalHeight; + this._leftWidth = (_e = options.leftWidth) != null ? _e : this._leftWidth; + this._rightWidth = (_f = options.rightWidth) != null ? _f : this._rightWidth; + this._topHeight = (_g = options.topHeight) != null ? _g : this._topHeight; + this._bottomHeight = (_h = options.bottomHeight) != null ? _h : this._bottomHeight; + this.updateUvs(); + this.updatePositions(); + } + /** Updates the positions of the vertices. */ + updatePositions() { + const positions = this.positions; + const w = this._leftWidth + this._rightWidth; + const scaleW = this.width > w ? 1 : this.width / w; + const h = this._topHeight + this._bottomHeight; + const scaleH = this.height > h ? 1 : this.height / h; + const scale = Math.min(scaleW, scaleH); + positions[9] = positions[11] = positions[13] = positions[15] = this._topHeight * scale; + positions[17] = positions[19] = positions[21] = positions[23] = this.height - this._bottomHeight * scale; + positions[25] = positions[27] = positions[29] = positions[31] = this.height; + positions[2] = positions[10] = positions[18] = positions[26] = this._leftWidth * scale; + positions[4] = positions[12] = positions[20] = positions[28] = this.width - this._rightWidth * scale; + positions[6] = positions[14] = positions[22] = positions[30] = this.width; + this.getBuffer("aPosition").update(); + } + /** Updates the UVs of the vertices. */ + updateUvs() { + const uvs = this.uvs; + uvs[0] = uvs[8] = uvs[16] = uvs[24] = 0; + uvs[1] = uvs[3] = uvs[5] = uvs[7] = 0; + uvs[6] = uvs[14] = uvs[22] = uvs[30] = 1; + uvs[25] = uvs[27] = uvs[29] = uvs[31] = 1; + const _uvw = 1 / this._originalWidth; + const _uvh = 1 / this._originalHeight; + uvs[2] = uvs[10] = uvs[18] = uvs[26] = _uvw * this._leftWidth; + uvs[9] = uvs[11] = uvs[13] = uvs[15] = _uvh * this._topHeight; + uvs[4] = uvs[12] = uvs[20] = uvs[28] = 1 - _uvw * this._rightWidth; + uvs[17] = uvs[19] = uvs[21] = uvs[23] = 1 - _uvh * this._bottomHeight; + this.getBuffer("aUV").update(); + } + }; + /** The default options for the NineSliceGeometry. */ + _NineSliceGeometry.defaultOptions = { + /** The width of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane. */ + width: 100, + /** The height of the NineSlicePlane, setting this will actually modify the vertices and UV's of this plane. */ + height: 100, + /** The width of the left column. */ + leftWidth: 10, + /** The height of the top row. */ + topHeight: 10, + /** The width of the right column. */ + rightWidth: 10, + /** The height of the bottom row. */ + bottomHeight: 10, + /** The original width of the texture */ + originalWidth: 100, + /** The original height of the texture */ + originalHeight: 100 + }; + let NineSliceGeometry = _NineSliceGeometry; + + "use strict"; + class NineSliceSpritePipe { + constructor(renderer) { + this._gpuSpriteHash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + addRenderable(sprite, _instructionSet) { + const gpuSprite = this._getGpuSprite(sprite); + if (sprite._didSpriteUpdate) + this._updateBatchableSprite(sprite, gpuSprite); + this._renderer.renderPipes.batch.addToBatch(gpuSprite); + } + updateRenderable(sprite) { + const gpuSprite = this._gpuSpriteHash[sprite.uid]; + if (sprite._didSpriteUpdate) + this._updateBatchableSprite(sprite, gpuSprite); + gpuSprite.batcher.updateElement(gpuSprite); + } + validateRenderable(sprite) { + const texture = sprite._texture; + const gpuSprite = this._getGpuSprite(sprite); + if (gpuSprite.texture._source !== texture._source) { + return !gpuSprite.batcher.checkAndUpdateTexture(gpuSprite, texture); + } + return false; + } + destroyRenderable(sprite) { + const batchableSprite = this._gpuSpriteHash[sprite.uid]; + BigPool.return(batchableSprite); + this._gpuSpriteHash[sprite.uid] = null; + } + _updateBatchableSprite(sprite, batchableSprite) { + sprite._didSpriteUpdate = false; + batchableSprite.geometry.update(sprite); + batchableSprite.texture = sprite._texture; + } + _getGpuSprite(sprite) { + return this._gpuSpriteHash[sprite.uid] || this._initGPUSprite(sprite); + } + _initGPUSprite(sprite) { + const batchableMesh = new BatchableMesh(); + batchableMesh.geometry = new NineSliceGeometry(); + batchableMesh.mesh = sprite; + batchableMesh.texture = sprite._texture; + batchableMesh.roundPixels = this._renderer._roundPixels | sprite._roundPixels; + this._gpuSpriteHash[sprite.uid] = batchableMesh; + sprite.on("destroyed", () => { + this.destroyRenderable(sprite); + }); + return batchableMesh; + } + destroy() { + for (const i in this._gpuSpriteHash) { + const batchableMesh = this._gpuSpriteHash[i]; + batchableMesh.geometry.destroy(); + } + this._gpuSpriteHash = null; + this._renderer = null; + } + } + /** @ignore */ + NineSliceSpritePipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "nineSliceSprite" + }; + + "use strict"; + extensions.add(NineSliceSpritePipe); + + "use strict"; + class FilterPipe { + constructor(renderer) { + this._renderer = renderer; + } + push(filterEffect, container, instructionSet) { + const renderPipes = this._renderer.renderPipes; + renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "filter", + canBundle: false, + action: "pushFilter", + container, + filterEffect + }); + } + pop(_filterEffect, _container, instructionSet) { + this._renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "filter", + action: "popFilter", + canBundle: false + }); + } + execute(instruction) { + if (instruction.action === "pushFilter") { + this._renderer.filter.push(instruction); + } else if (instruction.action === "popFilter") { + this._renderer.filter.pop(); + } + } + destroy() { + this._renderer = null; + } + } + FilterPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "filter" + }; + + "use strict"; + const tempMatrix$1 = new Matrix(); + function getFastGlobalBounds(target, bounds) { + bounds.clear(); + _getGlobalBoundsRecursive(target, bounds); + if (!bounds.isValid) { + bounds.set(0, 0, 0, 0); + } + if (!target.renderGroup) { + bounds.applyMatrix(target.parentRenderGroup.worldTransform); + } else { + bounds.applyMatrix(target.renderGroup.localTransform); + } + return bounds; + } + function _getGlobalBoundsRecursive(target, bounds) { + if (target.localDisplayStatus !== 7 || !target.measurable) { + return; + } + const manageEffects = !!target.effects.length; + let localBounds = bounds; + if (target.renderGroup || manageEffects) { + localBounds = boundsPool.get().clear(); + } + if (target.boundsArea) { + bounds.addRect(target.boundsArea, target.worldTransform); + } else { + if (target.renderPipeId) { + const viewBounds = target.bounds; + localBounds.addFrame( + viewBounds.minX, + viewBounds.minY, + viewBounds.maxX, + viewBounds.maxY, + target.groupTransform + ); + } + const children = target.children; + for (let i = 0; i < children.length; i++) { + _getGlobalBoundsRecursive(children[i], localBounds); + } + } + if (manageEffects) { + let advanced = false; + for (let i = 0; i < target.effects.length; i++) { + if (target.effects[i].addBounds) { + if (!advanced) { + advanced = true; + localBounds.applyMatrix(target.parentRenderGroup.worldTransform); + } + target.effects[i].addBounds(localBounds, true); + } + } + if (advanced) { + localBounds.applyMatrix(target.parentRenderGroup.worldTransform.copyTo(tempMatrix$1).invert()); + bounds.addBounds(localBounds, target.relativeGroupTransform); + } + bounds.addBounds(localBounds); + boundsPool.return(localBounds); + } else if (target.renderGroup) { + bounds.addBounds(localBounds, target.relativeGroupTransform); + boundsPool.return(localBounds); + } + } + + "use strict"; + function getGlobalRenderableBounds(renderables, bounds) { + bounds.clear(); + const tempMatrix = bounds.matrix; + for (let i = 0; i < renderables.length; i++) { + const renderable = renderables[i]; + if (renderable.globalDisplayStatus < 7) { + continue; + } + bounds.matrix = renderable.worldTransform; + renderable.addBounds(bounds); + } + bounds.matrix = tempMatrix; + return bounds; + } + + "use strict"; + const quadGeometry = new Geometry({ + attributes: { + aPosition: { + buffer: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), + location: 0, + format: "float32x2", + stride: 2 * 4, + offset: 0 + } + }, + indexBuffer: new Uint32Array([0, 1, 2, 0, 2, 3]) + }); + class FilterSystem { + constructor(renderer) { + this._filterStackIndex = 0; + this._filterStack = []; + this._filterGlobalUniforms = new UniformGroup({ + uInputSize: { value: new Float32Array(4), type: "vec4" }, + uInputPixel: { value: new Float32Array(4), type: "vec4" }, + uInputClamp: { value: new Float32Array(4), type: "vec4" }, + uOutputFrame: { value: new Float32Array(4), type: "vec4" }, + uGlobalFrame: { value: new Float32Array(4), type: "vec4" }, + uOutputTexture: { value: new Float32Array(4), type: "vec4" } + }); + this._globalFilterBindGroup = new BindGroup({}); + this.renderer = renderer; + } + /** + * The back texture of the currently active filter. Requires the filter to have `blendRequired` set to true. + * @readonly + */ + get activeBackTexture() { + var _a; + return (_a = this._activeFilterData) == null ? void 0 : _a.backTexture; + } + push(instruction) { + var _a, _b; + const renderer = this.renderer; + const filters = instruction.filterEffect.filters; + if (!this._filterStack[this._filterStackIndex]) { + this._filterStack[this._filterStackIndex] = this._getFilterData(); + } + const filterData = this._filterStack[this._filterStackIndex]; + this._filterStackIndex++; + if (filters.length === 0) { + filterData.skip = true; + return; + } + const bounds = filterData.bounds; + if (instruction.renderables) { + getGlobalRenderableBounds(instruction.renderables, bounds); + } else if (instruction.filterEffect.filterArea) { + bounds.clear(); + bounds.addRect(instruction.filterEffect.filterArea); + bounds.applyMatrix(instruction.container.worldTransform); + } else { + getFastGlobalBounds(instruction.container, bounds); + } + const colorTextureSource = renderer.renderTarget.rootRenderTarget.colorTexture.source; + let resolution = colorTextureSource._resolution; + let padding = 0; + let antialias = colorTextureSource.antialias; + let blendRequired = false; + let enabled = false; + for (let i = 0; i < filters.length; i++) { + const filter = filters[i]; + resolution = Math.min(resolution, filter.resolution); + padding += filter.padding; + if (filter.antialias !== "inherit") { + if (filter.antialias === "on") { + antialias = true; + } else { + antialias = false; + } + } + const isCompatible = !!(filter.compatibleRenderers & renderer.type); + if (!isCompatible) { + enabled = false; + break; + } + if (filter.blendRequired && !((_b = (_a = renderer.backBuffer) == null ? void 0 : _a.useBackBuffer) != null ? _b : true)) { + warn("Blend filter requires backBuffer on WebGL renderer to be enabled. Set `useBackBuffer: true` in the renderer options."); + enabled = false; + break; + } + enabled = filter.enabled || enabled; + blendRequired = blendRequired || filter.blendRequired; + } + if (!enabled) { + filterData.skip = true; + return; + } + const viewPort = renderer.renderTarget.rootViewPort; + bounds.scale(resolution).fitBounds(0, viewPort.width, 0, viewPort.height).scale(1 / resolution).pad(padding).ceil(); + if (!bounds.isPositive) { + filterData.skip = true; + return; + } + filterData.skip = false; + filterData.bounds = bounds; + filterData.blendRequired = blendRequired; + filterData.container = instruction.container; + filterData.filterEffect = instruction.filterEffect; + filterData.previousRenderSurface = renderer.renderTarget.renderSurface; + filterData.inputTexture = TexturePool.getOptimalTexture( + bounds.width, + bounds.height, + resolution, + antialias + ); + renderer.renderTarget.bind(filterData.inputTexture, true); + renderer.globalUniforms.push({ + offset: bounds + }); + } + pop() { + const renderer = this.renderer; + this._filterStackIndex--; + const filterData = this._filterStack[this._filterStackIndex]; + if (filterData.skip) { + return; + } + this._activeFilterData = filterData; + const inputTexture = filterData.inputTexture; + const bounds = filterData.bounds; + let backTexture = Texture.EMPTY; + renderer.renderTarget.finishRenderPass(); + if (filterData.blendRequired) { + const previousBounds = this._filterStackIndex > 0 ? this._filterStack[this._filterStackIndex - 1].bounds : null; + const renderTarget = renderer.renderTarget.getRenderTarget(filterData.previousRenderSurface); + backTexture = this.getBackTexture(renderTarget, bounds, previousBounds); + } + filterData.backTexture = backTexture; + const filters = filterData.filterEffect.filters; + this._globalFilterBindGroup.setResource(inputTexture.source.style, 2); + this._globalFilterBindGroup.setResource(backTexture.source, 3); + renderer.globalUniforms.pop(); + if (filters.length === 1) { + filters[0].apply(this, inputTexture, filterData.previousRenderSurface, false); + TexturePool.returnTexture(inputTexture); + } else { + let flip = filterData.inputTexture; + let flop = TexturePool.getOptimalTexture( + bounds.width, + bounds.height, + flip.source._resolution, + false + ); + let i = 0; + for (i = 0; i < filters.length - 1; ++i) { + const filter = filters[i]; + filter.apply(this, flip, flop, true); + const t = flip; + flip = flop; + flop = t; + } + filters[i].apply(this, flip, filterData.previousRenderSurface, false); + TexturePool.returnTexture(flip); + TexturePool.returnTexture(flop); + } + if (filterData.blendRequired) { + TexturePool.returnTexture(backTexture); + } + } + getBackTexture(lastRenderSurface, bounds, previousBounds) { + const backgroundResolution = lastRenderSurface.colorTexture.source._resolution; + const backTexture = TexturePool.getOptimalTexture( + bounds.width, + bounds.height, + backgroundResolution, + false + ); + let x = bounds.minX; + let y = bounds.minY; + if (previousBounds) { + x -= previousBounds.minX; + y -= previousBounds.minY; + } + x = Math.floor(x * backgroundResolution); + y = Math.floor(y * backgroundResolution); + const width = Math.ceil(bounds.width * backgroundResolution); + const height = Math.ceil(bounds.height * backgroundResolution); + this.renderer.renderTarget.copyToTexture( + lastRenderSurface, + backTexture, + { x, y }, + { width, height }, + { x: 0, y: 0 } + ); + return backTexture; + } + applyFilter(filter, input, output, clear) { + const renderer = this.renderer; + const filterData = this._filterStack[this._filterStackIndex]; + const bounds = filterData.bounds; + const offset = Point.shared; + const previousRenderSurface = filterData.previousRenderSurface; + const isFinalTarget = previousRenderSurface === output; + let resolution = this.renderer.renderTarget.rootRenderTarget.colorTexture.source._resolution; + let currentIndex = this._filterStackIndex - 1; + while (currentIndex > 0 && this._filterStack[currentIndex].skip) { + --currentIndex; + } + if (currentIndex > 0) { + resolution = this._filterStack[currentIndex].inputTexture.source._resolution; + } + const filterUniforms = this._filterGlobalUniforms; + const uniforms = filterUniforms.uniforms; + const outputFrame = uniforms.uOutputFrame; + const inputSize = uniforms.uInputSize; + const inputPixel = uniforms.uInputPixel; + const inputClamp = uniforms.uInputClamp; + const globalFrame = uniforms.uGlobalFrame; + const outputTexture = uniforms.uOutputTexture; + if (isFinalTarget) { + let lastIndex = this._filterStackIndex; + while (lastIndex > 0) { + lastIndex--; + const filterData2 = this._filterStack[this._filterStackIndex - 1]; + if (!filterData2.skip) { + offset.x = filterData2.bounds.minX; + offset.y = filterData2.bounds.minY; + break; + } + } + outputFrame[0] = bounds.minX - offset.x; + outputFrame[1] = bounds.minY - offset.y; + } else { + outputFrame[0] = 0; + outputFrame[1] = 0; + } + outputFrame[2] = input.frame.width; + outputFrame[3] = input.frame.height; + inputSize[0] = input.source.width; + inputSize[1] = input.source.height; + inputSize[2] = 1 / inputSize[0]; + inputSize[3] = 1 / inputSize[1]; + inputPixel[0] = input.source.pixelWidth; + inputPixel[1] = input.source.pixelHeight; + inputPixel[2] = 1 / inputPixel[0]; + inputPixel[3] = 1 / inputPixel[1]; + inputClamp[0] = 0.5 * inputPixel[2]; + inputClamp[1] = 0.5 * inputPixel[3]; + inputClamp[2] = input.frame.width * inputSize[2] - 0.5 * inputPixel[2]; + inputClamp[3] = input.frame.height * inputSize[3] - 0.5 * inputPixel[3]; + const rootTexture = this.renderer.renderTarget.rootRenderTarget.colorTexture; + globalFrame[0] = offset.x * resolution; + globalFrame[1] = offset.y * resolution; + globalFrame[2] = rootTexture.source.width * resolution; + globalFrame[3] = rootTexture.source.height * resolution; + const renderTarget = this.renderer.renderTarget.getRenderTarget(output); + renderer.renderTarget.bind(output, !!clear); + if (output instanceof Texture) { + outputTexture[0] = output.frame.width; + outputTexture[1] = output.frame.height; + } else { + outputTexture[0] = renderTarget.width; + outputTexture[1] = renderTarget.height; + } + outputTexture[2] = renderTarget.isRoot ? -1 : 1; + filterUniforms.update(); + if (renderer.renderPipes.uniformBatch) { + const batchUniforms = renderer.renderPipes.uniformBatch.getUboResource(filterUniforms); + this._globalFilterBindGroup.setResource(batchUniforms, 0); + } else { + this._globalFilterBindGroup.setResource(filterUniforms, 0); + } + this._globalFilterBindGroup.setResource(input.source, 1); + this._globalFilterBindGroup.setResource(input.source.style, 2); + filter.groups[0] = this._globalFilterBindGroup; + renderer.encoder.draw({ + geometry: quadGeometry, + shader: filter, + state: filter._state, + topology: "triangle-list" + }); + if (renderer.type === RendererType.WEBGL) { + renderer.renderTarget.finishRenderPass(); + } + } + _getFilterData() { + return { + skip: false, + inputTexture: null, + bounds: new Bounds(), + container: null, + filterEffect: null, + blendRequired: false, + previousRenderSurface: null + }; + } + /** + * Multiply _input normalized coordinates_ to this matrix to get _sprite texture normalized coordinates_. + * + * Use `outputMatrix * vTextureCoord` in the shader. + * @param outputMatrix - The matrix to output to. + * @param {Sprite} sprite - The sprite to map to. + * @returns The mapped matrix. + */ + calculateSpriteMatrix(outputMatrix, sprite) { + const data = this._activeFilterData; + const mappedMatrix = outputMatrix.set( + data.inputTexture._source.width, + 0, + 0, + data.inputTexture._source.height, + data.bounds.minX, + data.bounds.minY + ); + const worldTransform = sprite.worldTransform.copyTo(Matrix.shared); + worldTransform.invert(); + mappedMatrix.prepend(worldTransform); + mappedMatrix.scale( + 1 / sprite.texture.frame.width, + 1 / sprite.texture.frame.height + ); + mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y); + return mappedMatrix; + } + } + /** @ignore */ + FilterSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "filter" + }; + + "use strict"; + extensions.add(FilterSystem); + extensions.add(FilterPipe); + + "use strict"; + + var browserAll = { + __proto__: null + }; + + "use strict"; + + "use strict"; + const environments = []; + extensions.handleByNamedList(ExtensionType.Environment, environments); + async function loadEnvironmentExtensions(skip) { + if (skip) + return; + for (let i = 0; i < environments.length; i++) { + const env = environments[i]; + if (env.value.test()) { + await env.value.load(); + return; + } + } + } + async function autoDetectEnvironment(add) { + return loadEnvironmentExtensions(!add); + } + + "use strict"; + let unsafeEval; + function unsafeEvalSupported() { + if (typeof unsafeEval === "boolean") { + return unsafeEval; + } + try { + const func = new Function("param1", "param2", "param3", "return param1[param2] === param3;"); + unsafeEval = func({ a: "b" }, "a", "b") === true; + } catch (e) { + unsafeEval = false; + } + return unsafeEval; + } + + "use strict"; + + "use strict"; + var CLEAR = /* @__PURE__ */ ((CLEAR2) => { + CLEAR2[CLEAR2["NONE"] = 0] = "NONE"; + CLEAR2[CLEAR2["COLOR"] = 16384] = "COLOR"; + CLEAR2[CLEAR2["STENCIL"] = 1024] = "STENCIL"; + CLEAR2[CLEAR2["DEPTH"] = 256] = "DEPTH"; + CLEAR2[CLEAR2["COLOR_DEPTH"] = 16640] = "COLOR_DEPTH"; + CLEAR2[CLEAR2["COLOR_STENCIL"] = 17408] = "COLOR_STENCIL"; + CLEAR2[CLEAR2["DEPTH_STENCIL"] = 1280] = "DEPTH_STENCIL"; + CLEAR2[CLEAR2["ALL"] = 17664] = "ALL"; + return CLEAR2; + })(CLEAR || {}); + + "use strict"; + class SystemRunner { + /** + * @param name - The function name that will be executed on the listeners added to this Runner. + */ + constructor(name) { + this.items = []; + this._name = name; + } + /* eslint-disable jsdoc/require-param, jsdoc/check-param-names */ + /** + * Dispatch/Broadcast Runner to all listeners added to the queue. + * @param {...any} params - (optional) parameters to pass to each listener + */ + /* eslint-enable jsdoc/require-param, jsdoc/check-param-names */ + emit(a0, a1, a2, a3, a4, a5, a6, a7) { + const { name, items } = this; + for (let i = 0, len = items.length; i < len; i++) { + items[i][name](a0, a1, a2, a3, a4, a5, a6, a7); + } + return this; + } + /** + * Add a listener to the Runner + * + * Runners do not need to have scope or functions passed to them. + * All that is required is to pass the listening object and ensure that it has contains a function that has the same name + * as the name provided to the Runner when it was created. + * + * Eg A listener passed to this Runner will require a 'complete' function. + * + * ``` + * import { Runner } from 'pixi.js'; + * + * const complete = new Runner('complete'); + * ``` + * + * The scope used will be the object itself. + * @param {any} item - The object that will be listening. + */ + add(item) { + if (item[this._name]) { + this.remove(item); + this.items.push(item); + } + return this; + } + /** + * Remove a single listener from the dispatch queue. + * @param {any} item - The listener that you would like to remove. + */ + remove(item) { + const index = this.items.indexOf(item); + if (index !== -1) { + this.items.splice(index, 1); + } + return this; + } + /** + * Check to see if the listener is already in the Runner + * @param {any} item - The listener that you would like to check. + */ + contains(item) { + return this.items.indexOf(item) !== -1; + } + /** Remove all listeners from the Runner */ + removeAll() { + this.items.length = 0; + return this; + } + /** Remove all references, don't use after this. */ + destroy() { + this.removeAll(); + this.items = null; + this._name = null; + } + /** + * `true` if there are no this Runner contains no listeners + * @readonly + */ + get empty() { + return this.items.length === 0; + } + /** + * The name of the runner. + * @readonly + */ + get name() { + return this._name; + } + } + + "use strict"; + var __defProp$D = Object.defineProperty; + var __getOwnPropSymbols$D = Object.getOwnPropertySymbols; + var __hasOwnProp$D = Object.prototype.hasOwnProperty; + var __propIsEnum$D = Object.prototype.propertyIsEnumerable; + var __defNormalProp$D = (obj, key, value) => key in obj ? __defProp$D(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$D = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$D.call(b, prop)) + __defNormalProp$D(a, prop, b[prop]); + if (__getOwnPropSymbols$D) + for (var prop of __getOwnPropSymbols$D(b)) { + if (__propIsEnum$D.call(b, prop)) + __defNormalProp$D(a, prop, b[prop]); + } + return a; + }; + const defaultRunners = [ + "init", + "destroy", + "contextChange", + "resolutionChange", + "reset", + "renderEnd", + "renderStart", + "render", + "update", + "postrender", + "prerender" + ]; + const _AbstractRenderer = class _AbstractRenderer extends EventEmitter { + /** + * Set up a system with a collection of SystemClasses and runners. + * Systems are attached dynamically to this class when added. + * @param config - the config for the system manager + */ + constructor(config) { + var _a; + super(); + this.runners = /* @__PURE__ */ Object.create(null); + this.renderPipes = /* @__PURE__ */ Object.create(null); + this._initOptions = {}; + this._systemsHash = /* @__PURE__ */ Object.create(null); + this.type = config.type; + this.name = config.name; + this.config = config; + const combinedRunners = [...defaultRunners, ...(_a = this.config.runners) != null ? _a : []]; + this._addRunners(...combinedRunners); + this._unsafeEvalCheck(); + } + /** + * Initialize the renderer. + * @param options - The options to use to create the renderer. + */ + async init(options = {}) { + const skip = options.skipExtensionImports === true ? true : options.manageImports === false; + await loadEnvironmentExtensions(skip); + this._addSystems(this.config.systems); + this._addPipes(this.config.renderPipes, this.config.renderPipeAdaptors); + for (const systemName in this._systemsHash) { + const system = this._systemsHash[systemName]; + const defaultSystemOptions = system.constructor.defaultOptions; + options = __spreadValues$D(__spreadValues$D({}, defaultSystemOptions), options); + } + options = __spreadValues$D(__spreadValues$D({}, _AbstractRenderer.defaultOptions), options); + this._roundPixels = options.roundPixels ? 1 : 0; + for (let i = 0; i < this.runners.init.items.length; i++) { + await this.runners.init.items[i].init(options); + } + this._initOptions = options; + } + render(args, deprecated) { + let options = args; + if (options instanceof Container) { + options = { container: options }; + if (deprecated) { + deprecation(v8_0_0, "passing a second argument is deprecated, please use render options instead"); + options.target = deprecated.renderTexture; + } + } + options.target || (options.target = this.view.renderTarget); + if (options.target === this.view.renderTarget) { + this._lastObjectRendered = options.container; + options.clearColor = this.background.colorRgba; + } + if (options.clearColor) { + const isRGBAArray = Array.isArray(options.clearColor) && options.clearColor.length === 4; + options.clearColor = isRGBAArray ? options.clearColor : Color.shared.setValue(options.clearColor).toArray(); + } + if (!options.transform) { + options.container.updateLocalTransform(); + options.transform = options.container.localTransform; + } + this.runners.prerender.emit(options); + this.runners.renderStart.emit(options); + this.runners.render.emit(options); + this.runners.renderEnd.emit(options); + this.runners.postrender.emit(options); + } + /** + * Resizes the WebGL view to the specified width and height. + * @param desiredScreenWidth - The desired width of the screen. + * @param desiredScreenHeight - The desired height of the screen. + * @param resolution - The resolution / device pixel ratio of the renderer. + */ + resize(desiredScreenWidth, desiredScreenHeight, resolution) { + this.view.resize(desiredScreenWidth, desiredScreenHeight, resolution); + this.emit("resize", this.view.screen.width, this.view.screen.height); + } + clear(options = {}) { + var _a; + const renderer = this; + options.target || (options.target = renderer.renderTarget.renderTarget); + options.clearColor || (options.clearColor = this.background.colorRgba); + (_a = options.clear) != null ? _a : options.clear = CLEAR.ALL; + const { clear, clearColor, target } = options; + Color.shared.setValue(clearColor != null ? clearColor : this.background.colorRgba); + renderer.renderTarget.clear(target, clear, Color.shared.toArray()); + } + /** The resolution / device pixel ratio of the renderer. */ + get resolution() { + return this.view.resolution; + } + set resolution(value) { + this.view.resolution = value; + this.runners.resolutionChange.emit(value); + } + /** + * Same as view.width, actual number of pixels in the canvas by horizontal. + * @member {number} + * @readonly + * @default 800 + */ + get width() { + return this.view.texture.frame.width; + } + /** + * Same as view.height, actual number of pixels in the canvas by vertical. + * @default 600 + */ + get height() { + return this.view.texture.frame.height; + } + // NOTE: this was `view` in v7 + /** + * The canvas element that everything is drawn to. + * @type {environment.ICanvas} + */ + get canvas() { + return this.view.canvas; + } + /** + * the last object rendered by the renderer. Useful for other plugins like interaction managers + * @readonly + */ + get lastObjectRendered() { + return this._lastObjectRendered; + } + /** + * Flag if we are rendering to the screen vs renderTexture + * @readonly + * @default true + */ + get renderingToScreen() { + const renderer = this; + return renderer.renderTarget.renderingToScreen; + } + /** + * Measurements of the screen. (0, 0, screenWidth, screenHeight). + * + * Its safe to use as filterArea or hitArea for the whole stage. + */ + get screen() { + return this.view.screen; + } + /** + * Create a bunch of runners based of a collection of ids + * @param runnerIds - the runner ids to add + */ + _addRunners(...runnerIds) { + runnerIds.forEach((runnerId) => { + this.runners[runnerId] = new SystemRunner(runnerId); + }); + } + _addSystems(systems) { + let i; + for (i in systems) { + const val = systems[i]; + this._addSystem(val.value, val.name); + } + } + /** + * Add a new system to the renderer. + * @param ClassRef - Class reference + * @param name - Property name for system, if not specified + * will use a static `name` property on the class itself. This + * name will be assigned as s property on the Renderer so make + * sure it doesn't collide with properties on Renderer. + * @returns Return instance of renderer + */ + _addSystem(ClassRef, name) { + const system = new ClassRef(this); + if (this[name]) { + throw new Error(`Whoops! The name "${name}" is already in use`); + } + this[name] = system; + this._systemsHash[name] = system; + for (const i in this.runners) { + this.runners[i].add(system); + } + return this; + } + _addPipes(pipes, pipeAdaptors) { + const adaptors = pipeAdaptors.reduce((acc, adaptor) => { + acc[adaptor.name] = adaptor.value; + return acc; + }, {}); + pipes.forEach((pipe) => { + const PipeClass = pipe.value; + const name = pipe.name; + const Adaptor = adaptors[name]; + this.renderPipes[name] = new PipeClass( + this, + Adaptor ? new Adaptor() : null + ); + }); + } + destroy(options = false) { + this.runners.destroy.items.reverse(); + this.runners.destroy.emit(options); + Object.values(this.runners).forEach((runner) => { + runner.destroy(); + }); + this._systemsHash = null; + this.renderPipes = null; + } + /** + * Generate a texture from a container. + * @param options - options or container target to use when generating the texture + * @returns a texture + */ + generateTexture(options) { + return this.textureGenerator.generateTexture(options); + } + /** + * Whether the renderer will round coordinates to whole pixels when rendering. + * Can be overridden on a per scene item basis. + */ + get roundPixels() { + return !!this._roundPixels; + } + /** + * Overrideable function by `pixi.js/unsafe-eval` to silence + * throwing an error if platform doesn't support unsafe-evals. + * @private + * @ignore + */ + _unsafeEvalCheck() { + if (!unsafeEvalSupported()) { + throw new Error("Current environment does not allow unsafe-eval, please use pixi.js/unsafe-eval module to enable support."); + } + } + }; + /** The default options for the renderer. */ + _AbstractRenderer.defaultOptions = { + /** + * Default resolution / device pixel ratio of the renderer. + * @default 1 + */ + resolution: 1, + /** + * Should the `failIfMajorPerformanceCaveat` flag be enabled as a context option used in the `isWebGLSupported` + * function. If set to true, a WebGL renderer can fail to be created if the browser thinks there could be + * performance issues when using WebGL. + * + * In PixiJS v6 this has changed from true to false by default, to allow WebGL to work in as many + * scenarios as possible. However, some users may have a poor experience, for example, if a user has a gpu or + * driver version blacklisted by the + * browser. + * + * If your application requires high performance rendering, you may wish to set this to false. + * We recommend one of two options if you decide to set this flag to false: + * + * 1: Use the Canvas renderer as a fallback in case high performance WebGL is + * not supported. + * + * 2: Call `isWebGLSupported` (which if found in the utils package) in your code before attempting to create a + * PixiJS renderer, and show an error message to the user if the function returns false, explaining that their + * device & browser combination does not support high performance WebGL. + * This is a much better strategy than trying to create a PixiJS renderer and finding it then fails. + * @default false + */ + failIfMajorPerformanceCaveat: false, + /** + * Should round pixels be forced when rendering? + * @default false + */ + roundPixels: false + }; + let AbstractRenderer = _AbstractRenderer; + + "use strict"; + let _isWebGLSupported; + function isWebGLSupported(failIfMajorPerformanceCaveat) { + if (_isWebGLSupported !== void 0) + return _isWebGLSupported; + _isWebGLSupported = (() => { + var _a; + const contextOptions = { + stencil: true, + failIfMajorPerformanceCaveat: failIfMajorPerformanceCaveat != null ? failIfMajorPerformanceCaveat : AbstractRenderer.defaultOptions.failIfMajorPerformanceCaveat + }; + try { + if (!DOMAdapter.get().getWebGLRenderingContext()) { + return false; + } + const canvas = DOMAdapter.get().createCanvas(); + let gl = canvas.getContext("webgl", contextOptions); + const success = !!((_a = gl == null ? void 0 : gl.getContextAttributes()) == null ? void 0 : _a.stencil); + if (gl) { + const loseContext = gl.getExtension("WEBGL_lose_context"); + if (loseContext) { + loseContext.loseContext(); + } + } + gl = null; + return success; + } catch (e) { + return false; + } + })(); + return _isWebGLSupported; + } + + "use strict"; + let _isWebGPUSupported; + async function isWebGPUSupported(options = {}) { + if (_isWebGPUSupported !== void 0) + return _isWebGPUSupported; + _isWebGPUSupported = await (async () => { + const gpu = DOMAdapter.get().getNavigator().gpu; + if (!gpu) { + return false; + } + try { + const adapter = await navigator.gpu.requestAdapter(options); + await adapter.requestDevice(); + return true; + } catch (e) { + return false; + } + })(); + return _isWebGPUSupported; + } + + "use strict"; + var __defProp$C = Object.defineProperty; + var __getOwnPropSymbols$C = Object.getOwnPropertySymbols; + var __hasOwnProp$C = Object.prototype.hasOwnProperty; + var __propIsEnum$C = Object.prototype.propertyIsEnumerable; + var __defNormalProp$C = (obj, key, value) => key in obj ? __defProp$C(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$C = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$C.call(b, prop)) + __defNormalProp$C(a, prop, b[prop]); + if (__getOwnPropSymbols$C) + for (var prop of __getOwnPropSymbols$C(b)) { + if (__propIsEnum$C.call(b, prop)) + __defNormalProp$C(a, prop, b[prop]); + } + return a; + }; + const renderPriority = ["webgl", "webgpu", "canvas"]; + async function autoDetectRenderer(options) { + var _a; + let preferredOrder = []; + if (options.preference) { + preferredOrder.push(options.preference); + renderPriority.forEach((item) => { + if (item !== options.preference) { + preferredOrder.push(item); + } + }); + } else { + preferredOrder = renderPriority.slice(); + } + let RendererClass; + let finalOptions = {}; + for (let i = 0; i < preferredOrder.length; i++) { + const rendererType = preferredOrder[i]; + if (rendererType === "webgpu" && await isWebGPUSupported()) { + const { WebGPURenderer } = await Promise.resolve().then(function () { return WebGPURenderer$1; }); + RendererClass = WebGPURenderer; + finalOptions = __spreadValues$C(__spreadValues$C({}, options), options.webgpu); + break; + } else if (rendererType === "webgl" && isWebGLSupported( + (_a = options.failIfMajorPerformanceCaveat) != null ? _a : AbstractRenderer.defaultOptions.failIfMajorPerformanceCaveat + )) { + const { WebGLRenderer } = await Promise.resolve().then(function () { return WebGLRenderer$1; }); + RendererClass = WebGLRenderer; + finalOptions = __spreadValues$C(__spreadValues$C({}, options), options.webgl); + break; + } else if (rendererType === "canvas") { + finalOptions = __spreadValues$C({}, options); + throw new Error("CanvasRenderer is not yet implemented"); + } + } + delete finalOptions.webgpu; + delete finalOptions.webgl; + if (!RendererClass) { + throw new Error("No available renderer for the current environment"); + } + const renderer = new RendererClass(); + await renderer.init(finalOptions); + return renderer; + } + + "use strict"; + var __defProp$B = Object.defineProperty; + var __getOwnPropSymbols$B = Object.getOwnPropertySymbols; + var __hasOwnProp$B = Object.prototype.hasOwnProperty; + var __propIsEnum$B = Object.prototype.propertyIsEnumerable; + var __defNormalProp$B = (obj, key, value) => key in obj ? __defProp$B(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$B = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$B.call(b, prop)) + __defNormalProp$B(a, prop, b[prop]); + if (__getOwnPropSymbols$B) + for (var prop of __getOwnPropSymbols$B(b)) { + if (__propIsEnum$B.call(b, prop)) + __defNormalProp$B(a, prop, b[prop]); + } + return a; + }; + const _Application = class _Application { + /** @ignore */ + constructor(...args) { + /** The root display container that's rendered. */ + this.stage = new Container(); + if (args[0] !== void 0) { + deprecation(v8_0_0, "Application constructor options are deprecated, please use Application.init() instead."); + } + } + /** + * @param options - The optional application and renderer parameters. + */ + async init(options) { + options = __spreadValues$B({}, options); + this.renderer = await autoDetectRenderer(options); + _Application._plugins.forEach((plugin) => { + plugin.init.call(this, options); + }); + } + /** Render the current stage. */ + render() { + this.renderer.render({ container: this.stage }); + } + /** + * Reference to the renderer's canvas element. + * @readonly + * @member {HTMLCanvasElement} + */ + get canvas() { + return this.renderer.canvas; + } + /** + * Reference to the renderer's canvas element. + * @member {HTMLCanvasElement} + * @deprecated since 8.0.0 + */ + get view() { + deprecation(v8_0_0, "Application.view is deprecated, please use Application.canvas instead."); + return this.renderer.canvas; + } + /** + * Reference to the renderer's screen rectangle. Its safe to use as `filterArea` or `hitArea` for the whole screen. + * @readonly + */ + get screen() { + return this.renderer.screen; + } + /** + * Destroys the application and all of its resources. + * @param {object|boolean}[rendererDestroyOptions=false] - The options for destroying the renderer. + * @param {boolean}[rendererDestroyOptions.removeView=false] - Removes the Canvas element from the DOM. + * @param {object|boolean} [options=false] - The options for destroying the stage. + * @param {boolean} [options.children=false] - If set to true, all the children will have their destroy method + * called as well. `options` will be passed on to those calls. + * @param {boolean} [options.texture=false] - Only used for children with textures e.g. Sprites. + * If options.children is set to true, + * it should destroy the texture of the child sprite. + * @param {boolean} [options.textureSource=false] - Only used for children with textures e.g. Sprites. + * If options.children is set to true, + * it should destroy the texture source of the child sprite. + * @param {boolean} [options.context=false] - Only used for children with graphicsContexts e.g. Graphics. + * If options.children is set to true, + * it should destroy the context of the child graphics. + */ + destroy(rendererDestroyOptions = false, options = false) { + const plugins = _Application._plugins.slice(0); + plugins.reverse(); + plugins.forEach((plugin) => { + plugin.destroy.call(this); + }); + this.stage.destroy(options); + this.stage = null; + this.renderer.destroy(rendererDestroyOptions); + this.renderer = null; + } + }; + /** + * Collection of installed plugins. + * @alias _plugins + */ + _Application._plugins = []; + let Application = _Application; + extensions.handleByList(ExtensionType.Application, Application._plugins); + + "use strict"; + + "use strict"; + + "use strict"; + class BitmapFont extends AbstractBitmapFont { + constructor(options, url) { + var _a; + super(); + const { textures, data } = options; + Object.keys(data.pages).forEach((key) => { + const pageData = data.pages[parseInt(key, 10)]; + const texture = textures[pageData.id]; + this.pages.push({ texture }); + }); + Object.keys(data.chars).forEach((key) => { + var _a2; + const charData = data.chars[key]; + const { + frame: textureFrame, + source: textureSource + } = textures[charData.page]; + const frameReal = new Rectangle( + charData.x + textureFrame.x, + charData.y + textureFrame.y, + charData.width, + charData.height + ); + const texture = new Texture({ + source: textureSource, + frame: frameReal + }); + this.chars[key] = { + id: key.codePointAt(0), + xOffset: charData.xOffset, + yOffset: charData.yOffset, + xAdvance: charData.xAdvance, + kerning: (_a2 = charData.kerning) != null ? _a2 : {}, + texture + }; + }); + this.baseRenderedFontSize = data.fontSize; + this.baseMeasurementFontSize = data.fontSize; + this.fontMetrics = { + ascent: 0, + descent: 0, + fontSize: data.fontSize + }; + this.baseLineOffset = data.baseLineOffset; + this.lineHeight = data.lineHeight; + this.fontFamily = data.fontFamily; + this.distanceField = (_a = data.distanceField) != null ? _a : { + type: "none", + range: 0 + }; + this.url = url; + } + /** Destroys the BitmapFont object. */ + destroy() { + super.destroy(); + for (let i = 0; i < this.pages.length; i++) { + const { texture } = this.pages[i]; + texture.destroy(true); + } + this.pages = null; + } + /** + * Generates a bitmap-font for the given style and character set + * @param options - Setup options for font generation. + * @returns Font generated by style options. + * @example + * import { BitmapFont, BitmapText } from 'pixi.js'; + * + * BitmapFont.install('TitleFont', { + * fontFamily: 'Arial', + * fontSize: 12, + * strokeThickness: 2, + * fill: 'purple', + * }); + * + * const title = new BitmapText({ text: 'This is the title', fontFamily: 'TitleFont' }); + */ + static install(options) { + BitmapFontManager.install(options); + } + /** + * Uninstalls a bitmap font from the cache. + * @param {string} name - The name of the bitmap font to uninstall. + */ + static uninstall(name) { + BitmapFontManager.uninstall(name); + } + } + + "use strict"; + const bitmapFontTextParser = { + test(data) { + return typeof data === "string" && data.startsWith("info face="); + }, + parse(txt) { + var _a, _b, _c; + const items = txt.match(/^[a-z]+\s+.+$/gm); + const rawData = { + info: [], + common: [], + page: [], + char: [], + chars: [], + kerning: [], + kernings: [], + distanceField: [] + }; + for (const i in items) { + const name = items[i].match(/^[a-z]+/gm)[0]; + const attributeList = items[i].match(/[a-zA-Z]+=([^\s"']+|"([^"]*)")/gm); + const itemData = {}; + for (const i2 in attributeList) { + const split = attributeList[i2].split("="); + const key = split[0]; + const strValue = split[1].replace(/"/gm, ""); + const floatValue = parseFloat(strValue); + const value = isNaN(floatValue) ? strValue : floatValue; + itemData[key] = value; + } + rawData[name].push(itemData); + } + const font = { + chars: {}, + pages: [], + lineHeight: 0, + fontSize: 0, + fontFamily: "", + distanceField: null, + baseLineOffset: 0 + }; + const [info] = rawData.info; + const [common] = rawData.common; + const [distanceField] = (_a = rawData.distanceField) != null ? _a : []; + if (distanceField) { + font.distanceField = { + range: parseInt(distanceField.distanceRange, 10), + type: distanceField.fieldType + }; + } + font.fontSize = parseInt(info.size, 10); + font.fontFamily = info.face; + font.lineHeight = parseInt(common.lineHeight, 10); + const page = rawData.page; + for (let i = 0; i < page.length; i++) { + font.pages.push({ + id: parseInt(page[i].id, 10) || 0, + file: page[i].file + }); + } + const map = {}; + font.baseLineOffset = font.lineHeight - parseInt(common.base, 10); + const char = rawData.char; + for (let i = 0; i < char.length; i++) { + const charNode = char[i]; + const id = parseInt(charNode.id, 10); + let letter = (_c = (_b = charNode.letter) != null ? _b : charNode.char) != null ? _c : String.fromCharCode(id); + if (letter === "space") + letter = " "; + map[id] = letter; + font.chars[letter] = { + id, + // texture deets.. + page: parseInt(charNode.page, 10) || 0, + x: parseInt(charNode.x, 10), + y: parseInt(charNode.y, 10), + width: parseInt(charNode.width, 10), + height: parseInt(charNode.height, 10), + xOffset: parseInt(charNode.xoffset, 10), + yOffset: parseInt(charNode.yoffset, 10), + xAdvance: parseInt(charNode.xadvance, 10), + kerning: {} + }; + } + const kerning = rawData.kerning || []; + for (let i = 0; i < kerning.length; i++) { + const first = parseInt(kerning[i].first, 10); + const second = parseInt(kerning[i].second, 10); + const amount = parseInt(kerning[i].amount, 10); + font.chars[map[second]].kerning[map[first]] = amount; + } + return font; + } + }; + + "use strict"; + const bitmapFontXMLParser = { + test(data) { + const xml = data; + return typeof xml !== "string" && "getElementsByTagName" in xml && xml.getElementsByTagName("page").length && xml.getElementsByTagName("info")[0].getAttribute("face") !== null; + }, + parse(xml) { + var _a, _b; + const data = { + chars: {}, + pages: [], + lineHeight: 0, + fontSize: 0, + fontFamily: "", + distanceField: null, + baseLineOffset: 0 + }; + const info = xml.getElementsByTagName("info")[0]; + const common = xml.getElementsByTagName("common")[0]; + const distanceField = xml.getElementsByTagName("distanceField")[0]; + if (distanceField) { + data.distanceField = { + type: distanceField.getAttribute("fieldType"), + range: parseInt(distanceField.getAttribute("distanceRange"), 10) + }; + } + const page = xml.getElementsByTagName("page"); + const char = xml.getElementsByTagName("char"); + const kerning = xml.getElementsByTagName("kerning"); + data.fontSize = parseInt(info.getAttribute("size"), 10); + data.fontFamily = info.getAttribute("face"); + data.lineHeight = parseInt(common.getAttribute("lineHeight"), 10); + for (let i = 0; i < page.length; i++) { + data.pages.push({ + id: parseInt(page[i].getAttribute("id"), 10) || 0, + file: page[i].getAttribute("file") + }); + } + const map = {}; + data.baseLineOffset = data.lineHeight - parseInt(common.getAttribute("base"), 10); + for (let i = 0; i < char.length; i++) { + const charNode = char[i]; + const id = parseInt(charNode.getAttribute("id"), 10); + let letter = (_b = (_a = charNode.getAttribute("letter")) != null ? _a : charNode.getAttribute("char")) != null ? _b : String.fromCharCode(id); + if (letter === "space") + letter = " "; + map[id] = letter; + data.chars[letter] = { + id, + // texture deets.. + page: parseInt(charNode.getAttribute("page"), 10) || 0, + x: parseInt(charNode.getAttribute("x"), 10), + y: parseInt(charNode.getAttribute("y"), 10), + width: parseInt(charNode.getAttribute("width"), 10), + height: parseInt(charNode.getAttribute("height"), 10), + // render deets.. + xOffset: parseInt(charNode.getAttribute("xoffset"), 10), + yOffset: parseInt(charNode.getAttribute("yoffset"), 10), + // + baseLineOffset, + xAdvance: parseInt(charNode.getAttribute("xadvance"), 10), + kerning: {} + }; + } + for (let i = 0; i < kerning.length; i++) { + const first = parseInt(kerning[i].getAttribute("first"), 10); + const second = parseInt(kerning[i].getAttribute("second"), 10); + const amount = parseInt(kerning[i].getAttribute("amount"), 10); + data.chars[map[second]].kerning[map[first]] = amount; + } + return data; + } + }; + + "use strict"; + const bitmapFontXMLStringParser = { + test(data) { + if (typeof data === "string" && data.includes("")) { + return bitmapFontXMLParser.test(DOMAdapter.get().parseXML(data)); + } + return false; + }, + parse(data) { + return bitmapFontXMLParser.parse(DOMAdapter.get().parseXML(data)); + } + }; + + "use strict"; + const validExtensions = [".xml", ".fnt"]; + const bitmapFontCachePlugin = { + extension: { + type: ExtensionType.CacheParser, + name: "cacheBitmapFont" + }, + test: (asset) => asset instanceof BitmapFont, + getCacheableAssets(keys, asset) { + const out = {}; + keys.forEach((key) => { + out[key] = asset; + out[`${key}-bitmap`] = asset; + }); + out[`${asset.fontFamily}-bitmap`] = asset; + return out; + } + }; + const loadBitmapFont = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Normal + }, + name: "loadBitmapFont", + test(url) { + return validExtensions.includes(path.extname(url).toLowerCase()); + }, + async testParse(data) { + return bitmapFontTextParser.test(data) || bitmapFontXMLStringParser.test(data); + }, + async parse(asset, data, loader) { + const bitmapFontData = bitmapFontTextParser.test(asset) ? bitmapFontTextParser.parse(asset) : bitmapFontXMLStringParser.parse(asset); + const { src } = data; + const { pages } = bitmapFontData; + const textureUrls = []; + const textureOptions = bitmapFontData.distanceField ? { + scaleMode: "linear", + alphaMode: "premultiply-alpha-on-upload", + autoGenerateMipmaps: false, + resolution: 1 + } : {}; + for (let i = 0; i < pages.length; ++i) { + const pageFile = pages[i].file; + let imagePath = path.join(path.dirname(src), pageFile); + imagePath = copySearchParams(imagePath, src); + textureUrls.push({ + src: imagePath, + data: textureOptions + }); + } + const loadedTextures = await loader.load(textureUrls); + const textures = textureUrls.map((url) => loadedTextures[url.src]); + const bitmapFont = new BitmapFont({ + data: bitmapFontData, + textures + }, src); + return bitmapFont; + }, + async load(url, _options) { + const response = await DOMAdapter.get().fetch(url); + return await response.text(); + }, + async unload(bitmapFont, _resolvedAsset, loader) { + await Promise.all(bitmapFont.pages.map((page) => loader.unload(page.texture.source._sourceOrigin))); + bitmapFont.destroy(); + } + }; + + "use strict"; + class BackgroundLoader { + /** + * @param loader + * @param verbose - should the loader log to the console + */ + constructor(loader, verbose = false) { + this._loader = loader; + this._assetList = []; + this._isLoading = false; + this._maxConcurrent = 1; + this.verbose = verbose; + } + /** + * Adds an array of assets to load. + * @param assetUrls - assets to load + */ + add(assetUrls) { + assetUrls.forEach((a) => { + this._assetList.push(a); + }); + if (this.verbose) { + console.log("[BackgroundLoader] assets: ", this._assetList); + } + if (this._isActive && !this._isLoading) { + void this._next(); + } + } + /** + * Loads the next set of assets. Will try to load as many assets as it can at the same time. + * + * The max assets it will try to load at one time will be 4. + */ + async _next() { + if (this._assetList.length && this._isActive) { + this._isLoading = true; + const toLoad = []; + const toLoadAmount = Math.min(this._assetList.length, this._maxConcurrent); + for (let i = 0; i < toLoadAmount; i++) { + toLoad.push(this._assetList.pop()); + } + await this._loader.load(toLoad); + this._isLoading = false; + void this._next(); + } + } + /** + * Activate/Deactivate the loading. If set to true then it will immediately continue to load the next asset. + * @returns whether the class is active + */ + get active() { + return this._isActive; + } + set active(value) { + if (this._isActive === value) + return; + this._isActive = value; + if (value && !this._isLoading) { + void this._next(); + } + } + } + + "use strict"; + const cacheTextureArray = { + extension: { + type: ExtensionType.CacheParser, + name: "cacheTextureArray" + }, + test: (asset) => Array.isArray(asset) && asset.every((t) => t instanceof Texture), + getCacheableAssets: (keys, asset) => { + const out = {}; + keys.forEach((key) => { + asset.forEach((item, i) => { + out[key + (i === 0 ? "" : i + 1)] = item; + }); + }); + return out; + } + }; + + "use strict"; + async function testImageFormat(imageData) { + if ("Image" in globalThis) { + return new Promise((resolve) => { + const image = new Image(); + image.onload = () => { + resolve(true); + }; + image.onerror = () => { + resolve(false); + }; + image.src = imageData; + }); + } + if ("createImageBitmap" in globalThis && "fetch" in globalThis) { + try { + const blob = await (await fetch(imageData)).blob(); + await createImageBitmap(blob); + } catch (e) { + return false; + } + return true; + } + return false; + } + + "use strict"; + const detectAvif = { + extension: { + type: ExtensionType.DetectionParser, + priority: 1 + }, + test: async () => testImageFormat( + // eslint-disable-next-line max-len + "data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=" + ), + add: async (formats) => [...formats, "avif"], + remove: async (formats) => formats.filter((f) => f !== "avif") + }; + + "use strict"; + const imageFormats = ["png", "jpg", "jpeg"]; + const detectDefaults = { + extension: { + type: ExtensionType.DetectionParser, + priority: -1 + }, + test: () => Promise.resolve(true), + add: async (formats) => [...formats, ...imageFormats], + remove: async (formats) => formats.filter((f) => !imageFormats.includes(f)) + }; + + "use strict"; + const inWorker = "WorkerGlobalScope" in globalThis && globalThis instanceof globalThis.WorkerGlobalScope; + function testVideoFormat(mimeType) { + if (inWorker) { + return false; + } + const video = document.createElement("video"); + return video.canPlayType(mimeType) !== ""; + } + + "use strict"; + const detectMp4 = { + extension: { + type: ExtensionType.DetectionParser, + priority: 0 + }, + test: async () => testVideoFormat("video/mp4"), + add: async (formats) => [...formats, "mp4", "m4v"], + remove: async (formats) => formats.filter((f) => f !== "mp4" && f !== "m4v") + }; + + "use strict"; + const detectOgv = { + extension: { + type: ExtensionType.DetectionParser, + priority: 0 + }, + test: async () => testVideoFormat("video/ogg"), + add: async (formats) => [...formats, "ogv"], + remove: async (formats) => formats.filter((f) => f !== "ogv") + }; + + "use strict"; + const detectWebm = { + extension: { + type: ExtensionType.DetectionParser, + priority: 0 + }, + test: async () => testVideoFormat("video/webm"), + add: async (formats) => [...formats, "webm"], + remove: async (formats) => formats.filter((f) => f !== "webm") + }; + + "use strict"; + const detectWebp = { + extension: { + type: ExtensionType.DetectionParser, + priority: 0 + }, + test: async () => testImageFormat( + "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=" + ), + add: async (formats) => [...formats, "webp"], + remove: async (formats) => formats.filter((f) => f !== "webp") + }; + + "use strict"; + var __defProp$A = Object.defineProperty; + var __defProps$h = Object.defineProperties; + var __getOwnPropDescs$h = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$A = Object.getOwnPropertySymbols; + var __hasOwnProp$A = Object.prototype.hasOwnProperty; + var __propIsEnum$A = Object.prototype.propertyIsEnumerable; + var __defNormalProp$A = (obj, key, value) => key in obj ? __defProp$A(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$A = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$A.call(b, prop)) + __defNormalProp$A(a, prop, b[prop]); + if (__getOwnPropSymbols$A) + for (var prop of __getOwnPropSymbols$A(b)) { + if (__propIsEnum$A.call(b, prop)) + __defNormalProp$A(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$h = (a, b) => __defProps$h(a, __getOwnPropDescs$h(b)); + class Loader { + constructor() { + this._parsers = []; + this._parsersValidated = false; + /** + * All loader parsers registered + * @type {assets.LoaderParser[]} + */ + this.parsers = new Proxy(this._parsers, { + set: (target, key, value) => { + this._parsersValidated = false; + target[key] = value; + return true; + } + }); + /** Cache loading promises that ae currently active */ + this.promiseCache = {}; + } + /** function used for testing */ + reset() { + this._parsersValidated = false; + this.promiseCache = {}; + } + /** + * Used internally to generate a promise for the asset to be loaded. + * @param url - The URL to be loaded + * @param data - any custom additional information relevant to the asset being loaded + * @returns - a promise that will resolve to an Asset for example a Texture of a JSON object + */ + _getLoadPromiseAndParser(url, data) { + const result = { + promise: null, + parser: null + }; + result.promise = (async () => { + var _a, _b; + let asset = null; + let parser = null; + if (data.loadParser) { + parser = this._parserHash[data.loadParser]; + if (!parser) { + warn(`[Assets] specified load parser "${data.loadParser}" not found while loading ${url}`); + } + } + if (!parser) { + for (let i = 0; i < this.parsers.length; i++) { + const parserX = this.parsers[i]; + if (parserX.load && ((_a = parserX.test) == null ? void 0 : _a.call(parserX, url, data, this))) { + parser = parserX; + break; + } + } + if (!parser) { + warn(`[Assets] ${url} could not be loaded as we don't know how to parse it, ensure the correct parser has been added`); + return null; + } + } + asset = await parser.load(url, data, this); + result.parser = parser; + for (let i = 0; i < this.parsers.length; i++) { + const parser2 = this.parsers[i]; + if (parser2.parse) { + if (parser2.parse && await ((_b = parser2.testParse) == null ? void 0 : _b.call(parser2, asset, data, this))) { + asset = await parser2.parse(asset, data, this) || asset; + result.parser = parser2; + } + } + } + return asset; + })(); + return result; + } + async load(assetsToLoadIn, onProgress) { + if (!this._parsersValidated) { + this._validateParsers(); + } + let count = 0; + const assets = {}; + const singleAsset = isSingleItem(assetsToLoadIn); + const assetsToLoad = convertToList(assetsToLoadIn, (item) => ({ + alias: [item], + src: item + })); + const total = assetsToLoad.length; + const promises = assetsToLoad.map(async (asset) => { + const url = path.toAbsolute(asset.src); + if (!assets[asset.src]) { + try { + if (!this.promiseCache[url]) { + this.promiseCache[url] = this._getLoadPromiseAndParser(url, asset); + } + assets[asset.src] = await this.promiseCache[url].promise; + if (onProgress) + onProgress(++count / total); + } catch (e) { + delete this.promiseCache[url]; + delete assets[asset.src]; + throw new Error(`[Loader.load] Failed to load ${url}. +${e}`); + } + } + }); + await Promise.all(promises); + return singleAsset ? assets[assetsToLoad[0].src] : assets; + } + /** + * Unloads one or more assets. Any unloaded assets will be destroyed, freeing up memory for your app. + * The parser that created the asset, will be the one that unloads it. + * @example + * // Single asset: + * const asset = await Loader.load('cool.png'); + * + * await Loader.unload('cool.png'); + * + * console.log(asset.destroyed); // true + * @param assetsToUnloadIn - urls that you want to unload, or a single one! + */ + async unload(assetsToUnloadIn) { + const assetsToUnload = convertToList(assetsToUnloadIn, (item) => ({ + alias: [item], + src: item + })); + const promises = assetsToUnload.map(async (asset) => { + var _a, _b; + const url = path.toAbsolute(asset.src); + const loadPromise = this.promiseCache[url]; + if (loadPromise) { + const loadedAsset = await loadPromise.promise; + delete this.promiseCache[url]; + await ((_b = (_a = loadPromise.parser) == null ? void 0 : _a.unload) == null ? void 0 : _b.call(_a, loadedAsset, asset, this)); + } + }); + await Promise.all(promises); + } + /** validates our parsers, right now it only checks for name conflicts but we can add more here as required! */ + _validateParsers() { + this._parsersValidated = true; + this._parserHash = this._parsers.filter((parser) => parser.name).reduce((hash, parser) => { + if (!parser.name) { + warn(`[Assets] loadParser should have a name`); + } else if (hash[parser.name]) { + warn(`[Assets] loadParser name conflict "${parser.name}"`); + } + return __spreadProps$h(__spreadValues$A({}, hash), { [parser.name]: parser }); + }, {}); + } + } + + "use strict"; + function checkDataUrl(url, mimes) { + if (Array.isArray(mimes)) { + for (const mime of mimes) { + if (url.startsWith(`data:${mime}`)) + return true; + } + return false; + } + return url.startsWith(`data:${mimes}`); + } + + "use strict"; + function checkExtension(url, extension) { + const tempURL = url.split("?")[0]; + const ext = path.extname(tempURL).toLowerCase(); + if (Array.isArray(extension)) { + return extension.includes(ext); + } + return ext === extension; + } + + "use strict"; + const validJSONExtension = ".json"; + const validJSONMIME = "application/json"; + const loadJson = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Low + }, + name: "loadJson", + test(url) { + return checkDataUrl(url, validJSONMIME) || checkExtension(url, validJSONExtension); + }, + async load(url) { + const response = await DOMAdapter.get().fetch(url); + const json = await response.json(); + return json; + } + }; + + "use strict"; + const validTXTExtension = ".txt"; + const validTXTMIME = "text/plain"; + const loadTxt = { + name: "loadTxt", + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Low, + name: "loadTxt" + }, + test(url) { + return checkDataUrl(url, validTXTMIME) || checkExtension(url, validTXTExtension); + }, + async load(url) { + const response = await DOMAdapter.get().fetch(url); + const txt = await response.text(); + return txt; + } + }; + + "use strict"; + var __defProp$z = Object.defineProperty; + var __defProps$g = Object.defineProperties; + var __getOwnPropDescs$g = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$z = Object.getOwnPropertySymbols; + var __hasOwnProp$z = Object.prototype.hasOwnProperty; + var __propIsEnum$z = Object.prototype.propertyIsEnumerable; + var __defNormalProp$z = (obj, key, value) => key in obj ? __defProp$z(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$z = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$z.call(b, prop)) + __defNormalProp$z(a, prop, b[prop]); + if (__getOwnPropSymbols$z) + for (var prop of __getOwnPropSymbols$z(b)) { + if (__propIsEnum$z.call(b, prop)) + __defNormalProp$z(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$g = (a, b) => __defProps$g(a, __getOwnPropDescs$g(b)); + const validWeights = [ + "normal", + "bold", + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900" + ]; + const validFontExtensions = [".ttf", ".otf", ".woff", ".woff2"]; + const validFontMIMEs = [ + "font/ttf", + "font/otf", + "font/woff", + "font/woff2" + ]; + const CSS_IDENT_TOKEN_REGEX = /^(--|-?[A-Z_])[0-9A-Z_-]*$/i; + function getFontFamilyName(url) { + const ext = path.extname(url); + const name = path.basename(url, ext); + const nameWithSpaces = name.replace(/(-|_)/g, " "); + const nameTokens = nameWithSpaces.toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)); + let valid = nameTokens.length > 0; + for (const token of nameTokens) { + if (!token.match(CSS_IDENT_TOKEN_REGEX)) { + valid = false; + break; + } + } + let fontFamilyName = nameTokens.join(" "); + if (!valid) { + fontFamilyName = `"${fontFamilyName.replace(/[\\"]/g, "\\$&")}"`; + } + return fontFamilyName; + } + const validURICharactersRegex = /^[0-9A-Za-z%:/?#\[\]@!\$&'()\*\+,;=\-._~]*$/; + function encodeURIWhenNeeded(uri) { + if (validURICharactersRegex.test(uri)) { + return uri; + } + return encodeURI(uri); + } + const loadWebFont = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Low + }, + name: "loadWebFont", + test(url) { + return checkDataUrl(url, validFontMIMEs) || checkExtension(url, validFontExtensions); + }, + async load(url, options) { + var _a, _b, _c, _d, _e, _f; + const fonts = DOMAdapter.get().getFontFaceSet(); + if (fonts) { + const fontFaces = []; + const name = (_b = (_a = options.data) == null ? void 0 : _a.family) != null ? _b : getFontFamilyName(url); + const weights = (_e = (_d = (_c = options.data) == null ? void 0 : _c.weights) == null ? void 0 : _d.filter((weight) => validWeights.includes(weight))) != null ? _e : ["normal"]; + const data = (_f = options.data) != null ? _f : {}; + for (let i = 0; i < weights.length; i++) { + const weight = weights[i]; + const font = new FontFace(name, `url(${encodeURIWhenNeeded(url)})`, __spreadProps$g(__spreadValues$z({}, data), { + weight + })); + await font.load(); + fonts.add(font); + fontFaces.push(font); + } + Cache.set(`${name}-and-url`, { + url, + fontFaces + }); + return fontFaces.length === 1 ? fontFaces[0] : fontFaces; + } + warn("[loadWebFont] FontFace API is not supported. Skipping loading font"); + return null; + }, + unload(font) { + (Array.isArray(font) ? font : [font]).forEach((t) => { + Cache.remove(t.family); + DOMAdapter.get().getFontFaceSet().delete(t); + }); + } + }; + + "use strict"; + function getResolutionOfUrl(url, defaultValue = 1) { + var _a; + const resolution = (_a = Resolver.RETINA_PREFIX) == null ? void 0 : _a.exec(url); + if (resolution) { + return parseFloat(resolution[1]); + } + return defaultValue; + } + + "use strict"; + function createTexture(source, loader, url) { + source.label = url; + source._sourceOrigin = url; + const texture = new Texture({ + source, + label: url + }); + const unload = () => { + delete loader.promiseCache[url]; + if (Cache.has(url)) { + Cache.remove(url); + } + }; + texture.source.once("destroy", () => { + if (loader.promiseCache[url]) { + warn("[Assets] A TextureSource managed by Assets was destroyed instead of unloaded! Use Assets.unload() instead of destroying the TextureSource."); + unload(); + } + }); + texture.once("destroy", () => { + if (!source.destroyed) { + warn("[Assets] A Texture managed by Assets was destroyed instead of unloaded! Use Assets.unload() instead of destroying the Texture."); + unload(); + } + }); + return texture; + } + + "use strict"; + var __defProp$y = Object.defineProperty; + var __getOwnPropSymbols$y = Object.getOwnPropertySymbols; + var __hasOwnProp$y = Object.prototype.hasOwnProperty; + var __propIsEnum$y = Object.prototype.propertyIsEnumerable; + var __defNormalProp$y = (obj, key, value) => key in obj ? __defProp$y(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$y = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$y.call(b, prop)) + __defNormalProp$y(a, prop, b[prop]); + if (__getOwnPropSymbols$y) + for (var prop of __getOwnPropSymbols$y(b)) { + if (__propIsEnum$y.call(b, prop)) + __defNormalProp$y(a, prop, b[prop]); + } + return a; + }; + var __objRest$e = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$y.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$y) + for (var prop of __getOwnPropSymbols$y(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$y.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + const validSVGExtension = ".svg"; + const validSVGMIME = "image/svg+xml"; + const loadSvg = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.Low, + name: "loadSVG" + }, + name: "loadSVG", + config: { + crossOrigin: "anonymous", + parseAsGraphicsContext: false + }, + test(url) { + return checkDataUrl(url, validSVGMIME) || checkExtension(url, validSVGExtension); + }, + async load(url, asset, loader) { + var _a; + if ((_a = asset.data.parseAsGraphicsContext) != null ? _a : this.config.parseAsGraphicsContext) { + return loadAsGraphics(url); + } + return loadAsTexture(url, asset, loader, this.config.crossOrigin); + }, + unload(asset) { + asset.destroy(true); + } + }; + async function loadAsTexture(url, asset, loader, crossOrigin) { + var _a, _b, _c, _d, _e; + const response = await DOMAdapter.get().fetch(url); + const blob = await response.blob(); + const blobUrl = URL.createObjectURL(blob); + const image = new Image(); + image.src = blobUrl; + image.crossOrigin = crossOrigin; + await image.decode(); + URL.revokeObjectURL(blobUrl); + const canvas = document.createElement("canvas"); + const context = canvas.getContext("2d"); + const resolution = ((_a = asset.data) == null ? void 0 : _a.resolution) || getResolutionOfUrl(url); + const width = (_c = (_b = asset.data) == null ? void 0 : _b.width) != null ? _c : image.width; + const height = (_e = (_d = asset.data) == null ? void 0 : _d.height) != null ? _e : image.height; + canvas.width = width * resolution; + canvas.height = height * resolution; + context.drawImage(image, 0, 0, width * resolution, height * resolution); + const _f = asset.data, { parseAsGraphicsContext: _p } = _f, rest = __objRest$e(_f, ["parseAsGraphicsContext"]); + const base = new ImageSource(__spreadValues$y({ + resource: canvas, + alphaMode: "premultiply-alpha-on-upload", + resolution + }, rest)); + return createTexture(base, loader, url); + } + async function loadAsGraphics(url) { + const response = await DOMAdapter.get().fetch(url); + const svgSource = await response.text(); + const context = new GraphicsContext(); + context.svg(svgSource); + return context; + } + + const WORKER_CODE$3 = "(function () {\n 'use strict';\n\n const WHITE_PNG = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII=\";\n async function checkImageBitmap() {\n try {\n if (typeof createImageBitmap !== \"function\")\n return false;\n const response = await fetch(WHITE_PNG);\n const imageBlob = await response.blob();\n const imageBitmap = await createImageBitmap(imageBlob);\n return imageBitmap.width === 1 && imageBitmap.height === 1;\n } catch (e) {\n return false;\n }\n }\n void checkImageBitmap().then((result) => {\n self.postMessage(result);\n });\n\n})();\n"; + let WORKER_URL$3 = null; + let WorkerInstance$3 = class WorkerInstance + { + constructor() + { + if (!WORKER_URL$3) + { + WORKER_URL$3 = URL.createObjectURL(new Blob([WORKER_CODE$3], { type: 'application/javascript' })); + } + this.worker = new Worker(WORKER_URL$3); + } + }; + WorkerInstance$3.revokeObjectURL = function revokeObjectURL() + { + if (WORKER_URL$3) + { + URL.revokeObjectURL(WORKER_URL$3); + WORKER_URL$3 = null; + } + }; + + const WORKER_CODE$2 = "(function () {\n 'use strict';\n\n async function loadImageBitmap(url) {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`[WorkerManager.loadImageBitmap] Failed to fetch ${url}: ${response.status} ${response.statusText}`);\n }\n const imageBlob = await response.blob();\n const imageBitmap = await createImageBitmap(imageBlob);\n return imageBitmap;\n }\n self.onmessage = async (event) => {\n try {\n const imageBitmap = await loadImageBitmap(event.data.data[0]);\n self.postMessage({\n data: imageBitmap,\n uuid: event.data.uuid,\n id: event.data.id\n }, [imageBitmap]);\n } catch (e) {\n self.postMessage({\n error: e,\n uuid: event.data.uuid,\n id: event.data.id\n });\n }\n };\n\n})();\n"; + let WORKER_URL$2 = null; + let WorkerInstance$2 = class WorkerInstance + { + constructor() + { + if (!WORKER_URL$2) + { + WORKER_URL$2 = URL.createObjectURL(new Blob([WORKER_CODE$2], { type: 'application/javascript' })); + } + this.worker = new Worker(WORKER_URL$2); + } + }; + WorkerInstance$2.revokeObjectURL = function revokeObjectURL() + { + if (WORKER_URL$2) + { + URL.revokeObjectURL(WORKER_URL$2); + WORKER_URL$2 = null; + } + }; + + "use strict"; + let UUID = 0; + let MAX_WORKERS; + class WorkerManagerClass { + constructor() { + this._initialized = false; + this._createdWorkers = 0; + this._workerPool = []; + this._queue = []; + this._resolveHash = {}; + } + isImageBitmapSupported() { + if (this._isImageBitmapSupported !== void 0) + return this._isImageBitmapSupported; + this._isImageBitmapSupported = new Promise((resolve) => { + const { worker } = new WorkerInstance$3(); + worker.addEventListener("message", (event) => { + worker.terminate(); + WorkerInstance$3.revokeObjectURL(); + resolve(event.data); + }); + }); + return this._isImageBitmapSupported; + } + loadImageBitmap(src) { + return this._run("loadImageBitmap", [src]); + } + async _initWorkers() { + if (this._initialized) + return; + this._initialized = true; + } + _getWorker() { + if (MAX_WORKERS === void 0) { + MAX_WORKERS = navigator.hardwareConcurrency || 4; + } + let worker = this._workerPool.pop(); + if (!worker && this._createdWorkers < MAX_WORKERS) { + this._createdWorkers++; + worker = new WorkerInstance$2().worker; + worker.addEventListener("message", (event) => { + this._complete(event.data); + this._returnWorker(event.target); + this._next(); + }); + } + return worker; + } + _returnWorker(worker) { + this._workerPool.push(worker); + } + _complete(data) { + if (data.error !== void 0) { + this._resolveHash[data.uuid].reject(data.error); + } else { + this._resolveHash[data.uuid].resolve(data.data); + } + this._resolveHash[data.uuid] = null; + } + async _run(id, args) { + await this._initWorkers(); + const promise = new Promise((resolve, reject) => { + this._queue.push({ id, arguments: args, resolve, reject }); + }); + this._next(); + return promise; + } + _next() { + if (!this._queue.length) + return; + const worker = this._getWorker(); + if (!worker) { + return; + } + const toDo = this._queue.pop(); + const id = toDo.id; + this._resolveHash[UUID] = { resolve: toDo.resolve, reject: toDo.reject }; + worker.postMessage({ + data: toDo.arguments, + uuid: UUID++, + id + }); + } + } + const WorkerManager = new WorkerManagerClass(); + + "use strict"; + var __defProp$x = Object.defineProperty; + var __getOwnPropSymbols$x = Object.getOwnPropertySymbols; + var __hasOwnProp$x = Object.prototype.hasOwnProperty; + var __propIsEnum$x = Object.prototype.propertyIsEnumerable; + var __defNormalProp$x = (obj, key, value) => key in obj ? __defProp$x(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$x = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$x.call(b, prop)) + __defNormalProp$x(a, prop, b[prop]); + if (__getOwnPropSymbols$x) + for (var prop of __getOwnPropSymbols$x(b)) { + if (__propIsEnum$x.call(b, prop)) + __defNormalProp$x(a, prop, b[prop]); + } + return a; + }; + const validImageExtensions = [".jpeg", ".jpg", ".png", ".webp", ".avif"]; + const validImageMIMEs = [ + "image/jpeg", + "image/png", + "image/webp", + "image/avif" + ]; + async function loadImageBitmap(url) { + const response = await DOMAdapter.get().fetch(url); + if (!response.ok) { + throw new Error(`[loadImageBitmap] Failed to fetch ${url}: ${response.status} ${response.statusText}`); + } + const imageBlob = await response.blob(); + const imageBitmap = await createImageBitmap(imageBlob); + return imageBitmap; + } + const loadTextures = { + name: "loadTextures", + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.High, + name: "loadTextures" + }, + config: { + preferWorkers: true, + preferCreateImageBitmap: true, + crossOrigin: "anonymous" + }, + test(url) { + return checkDataUrl(url, validImageMIMEs) || checkExtension(url, validImageExtensions); + }, + async load(url, asset, loader) { + var _a; + let src = null; + if (globalThis.createImageBitmap && this.config.preferCreateImageBitmap) { + if (this.config.preferWorkers && await WorkerManager.isImageBitmapSupported()) { + src = await WorkerManager.loadImageBitmap(url); + } else { + src = await loadImageBitmap(url); + } + } else { + src = await new Promise((resolve) => { + src = new Image(); + src.crossOrigin = this.config.crossOrigin; + src.src = url; + if (src.complete) { + resolve(src); + } else { + src.onload = () => { + resolve(src); + }; + } + }); + } + const base = new ImageSource(__spreadValues$x({ + resource: src, + alphaMode: "premultiply-alpha-on-upload", + resolution: ((_a = asset.data) == null ? void 0 : _a.resolution) || getResolutionOfUrl(url) + }, asset.data)); + return createTexture(base, loader, url); + }, + unload(texture) { + texture.destroy(true); + } + }; + + "use strict"; + var __defProp$w = Object.defineProperty; + var __defProps$f = Object.defineProperties; + var __getOwnPropDescs$f = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$w = Object.getOwnPropertySymbols; + var __hasOwnProp$w = Object.prototype.hasOwnProperty; + var __propIsEnum$w = Object.prototype.propertyIsEnumerable; + var __defNormalProp$w = (obj, key, value) => key in obj ? __defProp$w(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$w = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$w.call(b, prop)) + __defNormalProp$w(a, prop, b[prop]); + if (__getOwnPropSymbols$w) + for (var prop of __getOwnPropSymbols$w(b)) { + if (__propIsEnum$w.call(b, prop)) + __defNormalProp$w(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$f = (a, b) => __defProps$f(a, __getOwnPropDescs$f(b)); + const validVideoExtensions = [".mp4", ".m4v", ".webm", ".ogg", ".ogv", ".h264", ".avi", ".mov"]; + const validVideoMIMEs = validVideoExtensions.map((ext) => `video/${ext.substring(1)}`); + function crossOrigin(element, url, crossorigin) { + if (crossorigin === void 0 && !url.startsWith("data:")) { + element.crossOrigin = determineCrossOrigin(url); + } else if (crossorigin !== false) { + element.crossOrigin = typeof crossorigin === "string" ? crossorigin : "anonymous"; + } + } + function preloadVideo(element) { + return new Promise((resolve, reject) => { + element.addEventListener("canplaythrough", loaded); + element.addEventListener("error", error); + element.load(); + function loaded() { + cleanup(); + resolve(); + } + function error(err) { + cleanup(); + reject(err); + } + function cleanup() { + element.removeEventListener("canplaythrough", loaded); + element.removeEventListener("error", error); + } + }); + } + function determineCrossOrigin(url, loc = globalThis.location) { + if (url.startsWith("data:")) { + return ""; + } + loc = loc || globalThis.location; + const parsedUrl = new URL(url, document.baseURI); + if (parsedUrl.hostname !== loc.hostname || parsedUrl.port !== loc.port || parsedUrl.protocol !== loc.protocol) { + return "anonymous"; + } + return ""; + } + const loadVideoTextures = { + name: "loadVideo", + extension: { + type: ExtensionType.LoadParser, + name: "loadVideo" + }, + test(url) { + const isValidDataUrl = checkDataUrl(url, validVideoMIMEs); + const isValidExtension = checkExtension(url, validVideoExtensions); + return isValidDataUrl || isValidExtension; + }, + async load(url, asset, loader) { + var _a, _b; + const options = __spreadValues$w(__spreadProps$f(__spreadValues$w({}, VideoSource.defaultOptions), { + resolution: ((_a = asset.data) == null ? void 0 : _a.resolution) || getResolutionOfUrl(url), + alphaMode: ((_b = asset.data) == null ? void 0 : _b.alphaMode) || await detectVideoAlphaMode() + }), asset.data); + const videoElement = document.createElement("video"); + const attributeMap = { + preload: options.autoLoad !== false ? "auto" : void 0, + "webkit-playsinline": options.playsinline !== false ? "" : void 0, + playsinline: options.playsinline !== false ? "" : void 0, + muted: options.muted === true ? "" : void 0, + loop: options.loop === true ? "" : void 0, + autoplay: options.autoPlay !== false ? "" : void 0 + }; + Object.keys(attributeMap).forEach((key) => { + const value = attributeMap[key]; + if (value !== void 0) + videoElement.setAttribute(key, value); + }); + if (options.muted === true) { + videoElement.muted = true; + } + crossOrigin(videoElement, url, options.crossorigin); + const sourceElement = document.createElement("source"); + let mime; + if (url.startsWith("data:")) { + mime = url.slice(5, url.indexOf(";")); + } else if (!url.startsWith("blob:")) { + const ext = url.split("?")[0].slice(url.lastIndexOf(".") + 1).toLowerCase(); + mime = VideoSource.MIME_TYPES[ext] || `video/${ext}`; + } + sourceElement.src = url; + if (mime) { + sourceElement.type = mime; + } + return new Promise((resolve) => { + const onCanPlay = async () => { + const base = new VideoSource(__spreadProps$f(__spreadValues$w({}, options), { resource: videoElement })); + videoElement.removeEventListener("canplay", onCanPlay); + if (asset.data.preload) { + await preloadVideo(videoElement); + } + resolve(createTexture(base, loader, url)); + }; + videoElement.addEventListener("canplay", onCanPlay); + videoElement.appendChild(sourceElement); + }); + }, + unload(texture) { + texture.destroy(true); + } + }; + + "use strict"; + const resolveTextureUrl = { + extension: { + type: ExtensionType.ResolveParser, + name: "resolveTexture" + }, + test: loadTextures.test, + parse: (value) => { + var _a, _b; + return { + resolution: parseFloat((_b = (_a = Resolver.RETINA_PREFIX.exec(value)) == null ? void 0 : _a[1]) != null ? _b : "1"), + format: value.split(".").pop(), + src: value + }; + } + }; + + "use strict"; + const resolveJsonUrl = { + extension: { + type: ExtensionType.ResolveParser, + priority: -2, + name: "resolveJson" + }, + test: (value) => Resolver.RETINA_PREFIX.test(value) && value.endsWith(".json"), + parse: resolveTextureUrl.parse + }; + + "use strict"; + class AssetsClass { + constructor() { + this._detections = []; + this._initialized = false; + this.resolver = new Resolver(); + this.loader = new Loader(); + this.cache = Cache; + this._backgroundLoader = new BackgroundLoader(this.loader); + this._backgroundLoader.active = true; + this.reset(); + } + /** + * Best practice is to call this function before any loading commences + * Initiating is the best time to add any customization to the way things are loaded. + * + * you do not need to call this for the Assets class to work, only if you want to set any initial properties + * @param options - options to initialize the Assets manager with + */ + async init(options = {}) { + var _a, _b, _c; + if (this._initialized) { + warn("[Assets]AssetManager already initialized, did you load before calling this Assets.init()?"); + return; + } + this._initialized = true; + if (options.defaultSearchParams) { + this.resolver.setDefaultSearchParams(options.defaultSearchParams); + } + if (options.basePath) { + this.resolver.basePath = options.basePath; + } + if (options.bundleIdentifier) { + this.resolver.setBundleIdentifier(options.bundleIdentifier); + } + if (options.manifest) { + let manifest = options.manifest; + if (typeof manifest === "string") { + manifest = await this.load(manifest); + } + this.resolver.addManifest(manifest); + } + const resolutionPref = (_b = (_a = options.texturePreference) == null ? void 0 : _a.resolution) != null ? _b : 1; + const resolution = typeof resolutionPref === "number" ? [resolutionPref] : resolutionPref; + const formats = await this._detectFormats({ + preferredFormats: (_c = options.texturePreference) == null ? void 0 : _c.format, + skipDetections: options.skipDetections, + detections: this._detections + }); + this.resolver.prefer({ + params: { + format: formats, + resolution + } + }); + if (options.preferences) { + this.setPreferences(options.preferences); + } + } + /** + * Allows you to specify how to resolve any assets load requests. + * There are a few ways to add things here as shown below: + * @example + * import { Assets } from 'pixi.js'; + * + * // Simple + * Assets.add({alias: 'bunnyBooBoo', src: 'bunny.png'}); + * const bunny = await Assets.load('bunnyBooBoo'); + * + * // Multiple keys: + * Assets.add({alias: ['burger', 'chicken'], src: 'bunny.png'}); + * + * const bunny = await Assets.load('burger'); + * const bunny2 = await Assets.load('chicken'); + * + * // passing options to to the object + * Assets.add({ + * alias: 'bunnyBooBooSmooth', + * src: 'bunny{png,webp}', + * data: { scaleMode: SCALE_MODES.NEAREST }, // Base texture options + * }); + * + * // Multiple assets + * + * // The following all do the same thing: + * + * Assets.add({alias: 'bunnyBooBoo', src: 'bunny{png,webp}'}); + * + * Assets.add({ + * alias: 'bunnyBooBoo', + * src: [ + * 'bunny.png', + * 'bunny.webp', + * ], + * }); + * + * const bunny = await Assets.load('bunnyBooBoo'); // Will try to load WebP if available + * @param assets - the unresolved assets to add to the resolver + */ + add(assets) { + this.resolver.add(assets); + } + async load(urls, onProgress) { + if (!this._initialized) { + await this.init(); + } + const singleAsset = isSingleItem(urls); + const urlArray = convertToList(urls).map((url) => { + if (typeof url !== "string") { + const aliases = this.resolver.getAlias(url); + if (aliases.some((alias) => !this.resolver.hasKey(alias))) { + this.add(url); + } + return Array.isArray(aliases) ? aliases[0] : aliases; + } + if (!this.resolver.hasKey(url)) + this.add({ alias: url, src: url }); + return url; + }); + const resolveResults = this.resolver.resolve(urlArray); + const out = await this._mapLoadToResolve(resolveResults, onProgress); + return singleAsset ? out[urlArray[0]] : out; + } + /** + * This adds a bundle of assets in one go so that you can load them as a group. + * For example you could add a bundle for each screen in you pixi app + * @example + * import { Assets } from 'pixi.js'; + * + * Assets.addBundle('animals', [ + * { alias: 'bunny', src: 'bunny.png' }, + * { alias: 'chicken', src: 'chicken.png' }, + * { alias: 'thumper', src: 'thumper.png' }, + * ]); + * // or + * Assets.addBundle('animals', { + * bunny: 'bunny.png', + * chicken: 'chicken.png', + * thumper: 'thumper.png', + * }); + * + * const assets = await Assets.loadBundle('animals'); + * @param bundleId - the id of the bundle to add + * @param assets - a record of the asset or assets that will be chosen from when loading via the specified key + */ + addBundle(bundleId, assets) { + this.resolver.addBundle(bundleId, assets); + } + /** + * Bundles are a way to load multiple assets at once. + * If a manifest has been provided to the init function then you can load a bundle, or bundles. + * you can also add bundles via `addBundle` + * @example + * import { Assets } from 'pixi.js'; + * + * // Manifest Example + * const manifest = { + * bundles: [ + * { + * name: 'load-screen', + * assets: [ + * { + * alias: 'background', + * src: 'sunset.png', + * }, + * { + * alias: 'bar', + * src: 'load-bar.{png,webp}', + * }, + * ], + * }, + * { + * name: 'game-screen', + * assets: [ + * { + * alias: 'character', + * src: 'robot.png', + * }, + * { + * alias: 'enemy', + * src: 'bad-guy.png', + * }, + * ], + * }, + * ] + * }; + * + * await Assets.init({ manifest }); + * + * // Load a bundle... + * loadScreenAssets = await Assets.loadBundle('load-screen'); + * // Load another bundle... + * gameScreenAssets = await Assets.loadBundle('game-screen'); + * @param bundleIds - the bundle id or ids to load + * @param onProgress - Optional function that is called when progress on asset loading is made. + * The function is passed a single parameter, `progress`, which represents the percentage (0.0 - 1.0) + * of the assets loaded. Do not use this function to detect when assets are complete and available, + * instead use the Promise returned by this function. + * @returns all the bundles assets or a hash of assets for each bundle specified + */ + async loadBundle(bundleIds, onProgress) { + if (!this._initialized) { + await this.init(); + } + let singleAsset = false; + if (typeof bundleIds === "string") { + singleAsset = true; + bundleIds = [bundleIds]; + } + const resolveResults = this.resolver.resolveBundle(bundleIds); + const out = {}; + const keys = Object.keys(resolveResults); + let count = 0; + let total = 0; + const _onProgress = () => { + onProgress == null ? void 0 : onProgress(++count / total); + }; + const promises = keys.map((bundleId) => { + const resolveResult = resolveResults[bundleId]; + total += Object.keys(resolveResult).length; + return this._mapLoadToResolve(resolveResult, _onProgress).then((resolveResult2) => { + out[bundleId] = resolveResult2; + }); + }); + await Promise.all(promises); + return singleAsset ? out[bundleIds[0]] : out; + } + /** + * Initiate a background load of some assets. It will passively begin to load these assets in the background. + * So when you actually come to loading them you will get a promise that resolves to the loaded assets immediately + * + * An example of this might be that you would background load game assets after your inital load. + * then when you got to actually load your game screen assets when a player goes to the game - the loading + * would already have stared or may even be complete, saving you having to show an interim load bar. + * @example + * import { Assets } from 'pixi.js'; + * + * Assets.backgroundLoad('bunny.png'); + * + * // later on in your app... + * await Assets.loadBundle('bunny.png'); // Will resolve quicker as loading may have completed! + * @param urls - the url / urls you want to background load + */ + async backgroundLoad(urls) { + if (!this._initialized) { + await this.init(); + } + if (typeof urls === "string") { + urls = [urls]; + } + const resolveResults = this.resolver.resolve(urls); + this._backgroundLoader.add(Object.values(resolveResults)); + } + /** + * Initiate a background of a bundle, works exactly like backgroundLoad but for bundles. + * this can only be used if the loader has been initiated with a manifest + * @example + * import { Assets } from 'pixi.js'; + * + * await Assets.init({ + * manifest: { + * bundles: [ + * { + * name: 'load-screen', + * assets: [...], + * }, + * ... + * ], + * }, + * }); + * + * Assets.backgroundLoadBundle('load-screen'); + * + * // Later on in your app... + * await Assets.loadBundle('load-screen'); // Will resolve quicker as loading may have completed! + * @param bundleIds - the bundleId / bundleIds you want to background load + */ + async backgroundLoadBundle(bundleIds) { + if (!this._initialized) { + await this.init(); + } + if (typeof bundleIds === "string") { + bundleIds = [bundleIds]; + } + const resolveResults = this.resolver.resolveBundle(bundleIds); + Object.values(resolveResults).forEach((resolveResult) => { + this._backgroundLoader.add(Object.values(resolveResult)); + }); + } + /** + * Only intended for development purposes. + * This will wipe the resolver and caches. + * You will need to reinitialize the Asset + */ + reset() { + this.resolver.reset(); + this.loader.reset(); + this.cache.reset(); + this._initialized = false; + } + get(keys) { + if (typeof keys === "string") { + return Cache.get(keys); + } + const assets = {}; + for (let i = 0; i < keys.length; i++) { + assets[i] = Cache.get(keys[i]); + } + return assets; + } + /** + * helper function to map resolved assets back to loaded assets + * @param resolveResults - the resolve results from the resolver + * @param onProgress - the progress callback + */ + async _mapLoadToResolve(resolveResults, onProgress) { + const resolveArray = [...new Set(Object.values(resolveResults))]; + this._backgroundLoader.active = false; + const loadedAssets = await this.loader.load(resolveArray, onProgress); + this._backgroundLoader.active = true; + const out = {}; + resolveArray.forEach((resolveResult) => { + const asset = loadedAssets[resolveResult.src]; + const keys = [resolveResult.src]; + if (resolveResult.alias) { + keys.push(...resolveResult.alias); + } + keys.forEach((key) => { + out[key] = asset; + }); + Cache.set(keys, asset); + }); + return out; + } + /** + * Unload an asset or assets. As the Assets class is responsible for creating the assets via the `load` function + * this will make sure to destroy any assets and release them from memory. + * Once unloaded, you will need to load the asset again. + * + * Use this to help manage assets if you find that you have a large app and you want to free up memory. + * + * - it's up to you as the developer to make sure that textures are not actively being used when you unload them, + * Pixi won't break but you will end up with missing assets. Not a good look for the user! + * @example + * import { Assets } from 'pixi.js'; + * + * // Load a URL: + * const myImageTexture = await Assets.load('http://some.url.com/image.png'); // => returns a texture + * + * await Assets.unload('http://some.url.com/image.png') + * + * // myImageTexture will be destroyed now. + * + * // Unload multiple assets: + * const textures = await Assets.unload(['thumper', 'chicko']); + * @param urls - the urls to unload + */ + async unload(urls) { + if (!this._initialized) { + await this.init(); + } + const urlArray = convertToList(urls).map((url) => typeof url !== "string" ? url.src : url); + const resolveResults = this.resolver.resolve(urlArray); + await this._unloadFromResolved(resolveResults); + } + /** + * Bundles are a way to manage multiple assets at once. + * this will unload all files in a bundle. + * + * once a bundle has been unloaded, you need to load it again to have access to the assets. + * @example + * import { Assets } from 'pixi.js'; + * + * Assets.addBundle({ + * 'thumper': 'http://some.url.com/thumper.png', + * }) + * + * const assets = await Assets.loadBundle('thumper'); + * + * // Now to unload... + * + * await Assets.unloadBundle('thumper'); + * + * // All assets in the assets object will now have been destroyed and purged from the cache + * @param bundleIds - the bundle id or ids to unload + */ + async unloadBundle(bundleIds) { + if (!this._initialized) { + await this.init(); + } + bundleIds = convertToList(bundleIds); + const resolveResults = this.resolver.resolveBundle(bundleIds); + const promises = Object.keys(resolveResults).map((bundleId) => this._unloadFromResolved(resolveResults[bundleId])); + await Promise.all(promises); + } + async _unloadFromResolved(resolveResult) { + const resolveArray = Object.values(resolveResult); + resolveArray.forEach((resolveResult2) => { + Cache.remove(resolveResult2.src); + }); + await this.loader.unload(resolveArray); + } + /** + * Detects the supported formats for the browser, and returns an array of supported formats, respecting + * the users preferred formats order. + * @param options - the options to use when detecting formats + * @param options.preferredFormats - the preferred formats to use + * @param options.skipDetections - if we should skip the detections altogether + * @param options.detections - the detections to use + * @returns - the detected formats + */ + async _detectFormats(options) { + let formats = []; + if (options.preferredFormats) { + formats = Array.isArray(options.preferredFormats) ? options.preferredFormats : [options.preferredFormats]; + } + for (const detection of options.detections) { + if (options.skipDetections || await detection.test()) { + formats = await detection.add(formats); + } else if (!options.skipDetections) { + formats = await detection.remove(formats); + } + } + formats = formats.filter((format, index) => formats.indexOf(format) === index); + return formats; + } + /** All the detection parsers currently added to the Assets class. */ + get detections() { + return this._detections; + } + /** + * General setter for preferences. This is a helper function to set preferences on all parsers. + * @param preferences - the preferences to set + */ + setPreferences(preferences) { + this.loader.parsers.forEach((parser) => { + if (!parser.config) + return; + Object.keys(parser.config).filter((key) => key in preferences).forEach((key) => { + parser.config[key] = preferences[key]; + }); + }); + } + } + const Assets = new AssetsClass(); + extensions.handleByList(ExtensionType.LoadParser, Assets.loader.parsers).handleByList(ExtensionType.ResolveParser, Assets.resolver.parsers).handleByList(ExtensionType.CacheParser, Assets.cache.parsers).handleByList(ExtensionType.DetectionParser, Assets.detections); + extensions.add( + cacheTextureArray, + detectDefaults, + detectAvif, + detectWebp, + detectMp4, + detectOgv, + detectWebm, + loadJson, + loadTxt, + loadWebFont, + loadSvg, + loadTextures, + loadVideoTextures, + loadBitmapFont, + bitmapFontCachePlugin, + resolveTextureUrl, + resolveJsonUrl + ); + const assetKeyMap = { + loader: ExtensionType.LoadParser, + resolver: ExtensionType.ResolveParser, + cache: ExtensionType.CacheParser, + detection: ExtensionType.DetectionParser + }; + extensions.handle(ExtensionType.Asset, (extension) => { + const ref = extension.ref; + Object.entries(assetKeyMap).filter(([key]) => !!ref[key]).forEach(([key, type]) => { + var _a; + return extensions.add(Object.assign( + ref[key], + // Allow the function to optionally define it's own + // ExtensionMetadata, the use cases here is priority for LoaderParsers + { extension: (_a = ref[key].extension) != null ? _a : type } + )); + }); + }, (extension) => { + const ref = extension.ref; + Object.keys(assetKeyMap).filter((key) => !!ref[key]).forEach((key) => extensions.remove(ref[key])); + }); + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + const detectBasis = { + extension: { + type: ExtensionType.DetectionParser, + priority: 3 + }, + test: async () => { + if (await isWebGPUSupported()) + return true; + if (isWebGLSupported()) + return true; + return false; + }, + add: async (formats) => [...formats, "basis"], + remove: async (formats) => formats.filter((f) => f !== "basis") + }; + + "use strict"; + class CompressedSource extends TextureSource { + constructor(options) { + super(options); + this.uploadMethodId = "compressed"; + this.resource = options.resource; + this.mipLevelCount = this.resource.length; + } + } + + "use strict"; + let supportedGLCompressedTextureFormats; + function getSupportedGlCompressedTextureFormats() { + if (supportedGLCompressedTextureFormats) + return supportedGLCompressedTextureFormats; + const canvas = document.createElement("canvas"); + const gl = canvas.getContext("webgl"); + if (!gl) { + return []; + } + supportedGLCompressedTextureFormats = [ + // BC compressed formats usable if "texture-compression-bc" is both + // supported by the device/user agent and enabled in requestDevice. + // 'bc6h-rgb-ufloat' + // 'bc6h-rgb-float' + // 'bc7-rgba-unorm', + // 'bc7-rgba-unorm-srgb', + ...gl.getExtension("EXT_texture_compression_bptc") ? [ + "bc6h-rgb-ufloat", + "bc6h-rgb-float", + "bc7-rgba-unorm", + "bc7-rgba-unorm-srgb" + ] : [], + // BC compressed formats usable if "texture-compression-bc" is both + // supported by the device/user agent and enabled in requestDevice. + // 'bc1-rgba-unorm', + // 'bc1-rgba-unorm-srgb', + // 'bc4-r-unorm' + // 'bc4-r-snorm' + // 'bc5-rg-unorm' + // 'bc5-rg-snorm' + ...gl.getExtension("WEBGL_compressed_texture_s3tc") ? [ + "bc1-rgba-unorm", + "bc2-rgba-unorm", + "bc3-rgba-unorm" + ] : [], + ...gl.getExtension("WEBGL_compressed_texture_s3tc_srgb") ? [ + "bc1-rgba-unorm-srgb", + "bc2-rgba-unorm-srgb", + "bc3-rgba-unorm-srgb" + ] : [], + ...gl.getExtension("EXT_texture_compression_rgtc") ? [ + "bc4-r-unorm", + "bc4-r-snorm", + "bc5-rg-unorm", + "bc5-rg-snorm" + ] : [], + // ETC2 compressed formats usable if "texture-compression-etc2" is both + // supported by the device/user agent and enabled in requestDevice. + ...gl.getExtension("WEBGL_compressed_texture_etc") ? [ + "etc2-rgb8unorm", + "etc2-rgb8unorm-srgb", + "etc2-rgba8unorm", + "etc2-rgba8unorm-srgb", + "etc2-rgb8a1unorm", + "etc2-rgb8a1unorm-srgb", + "eac-r11unorm", + "eac-rg11unorm" + ] : [], + // 'eac-r11snorm', + // 'eac-rg11snorm', + // ASTC compressed formats usable if "texture-compression-astc" is both + // supported by the device/user agent and enabled in requestDevice. + ...gl.getExtension("WEBGL_compressed_texture_astc") ? [ + "astc-4x4-unorm", + "astc-4x4-unorm-srgb", + "astc-5x4-unorm", + "astc-5x4-unorm-srgb", + "astc-5x5-unorm", + "astc-5x5-unorm-srgb", + "astc-6x5-unorm", + "astc-6x5-unorm-srgb", + "astc-6x6-unorm", + "astc-6x6-unorm-srgb", + "astc-8x5-unorm", + "astc-8x5-unorm-srgb", + "astc-8x6-unorm", + "astc-8x6-unorm-srgb", + "astc-8x8-unorm", + "astc-8x8-unorm-srgb", + "astc-10x5-unorm", + "astc-10x5-unorm-srgb", + "astc-10x6-unorm", + "astc-10x6-unorm-srgb", + "astc-10x8-unorm", + "astc-10x8-unorm-srgb", + "astc-10x10-unorm", + "astc-10x10-unorm-srgb", + "astc-12x10-unorm", + "astc-12x10-unorm-srgb", + "astc-12x12-unorm", + "astc-12x12-unorm-srgb" + ] : [] + ]; + return supportedGLCompressedTextureFormats; + } + + "use strict"; + let supportedGPUCompressedTextureFormats; + async function getSupportedGPUCompressedTextureFormats() { + if (supportedGPUCompressedTextureFormats) + return supportedGPUCompressedTextureFormats; + const adapter = await navigator.gpu.requestAdapter(); + supportedGPUCompressedTextureFormats = [ + ...adapter.features.has("texture-compression-bc") ? [ + // BC compressed formats usable if "texture-compression-bc" is both + // supported by the device/user agent and enabled in requestDevice. + "bc1-rgba-unorm", + "bc1-rgba-unorm-srgb", + "bc2-rgba-unorm", + "bc2-rgba-unorm-srgb", + "bc3-rgba-unorm", + "bc3-rgba-unorm-srgb", + "bc4-r-unorm", + "bc4-r-snorm", + "bc5-rg-unorm", + "bc5-rg-snorm", + "bc6h-rgb-ufloat", + "bc6h-rgb-float", + "bc7-rgba-unorm", + "bc7-rgba-unorm-srgb" + ] : [], + ...adapter.features.has("texture-compression-etc2") ? [ + // ETC2 compressed formats usable if "texture-compression-etc2" is both + // supported by the device/user agent and enabled in requestDevice. + "etc2-rgb8unorm", + "etc2-rgb8unorm-srgb", + "etc2-rgb8a1unorm", + "etc2-rgb8a1unorm-srgb", + "etc2-rgba8unorm", + "etc2-rgba8unorm-srgb", + "eac-r11unorm", + "eac-r11snorm", + "eac-rg11unorm", + "eac-rg11snorm" + ] : [], + ...adapter.features.has("texture-compression-astc") ? [ + // ASTC compressed formats usable if "texture-compression-astc" is both + // supported by the device/user agent and enabled in requestDevice. + "astc-4x4-unorm", + "astc-4x4-unorm-srgb", + "astc-5x4-unorm", + "astc-5x4-unorm-srgb", + "astc-5x5-unorm", + "astc-5x5-unorm-srgb", + "astc-6x5-unorm", + "astc-6x5-unorm-srgb", + "astc-6x6-unorm", + "astc-6x6-unorm-srgb", + "astc-8x5-unorm", + "astc-8x5-unorm-srgb", + "astc-8x6-unorm", + "astc-8x6-unorm-srgb", + "astc-8x8-unorm", + "astc-8x8-unorm-srgb", + "astc-10x5-unorm", + "astc-10x5-unorm-srgb", + "astc-10x6-unorm", + "astc-10x6-unorm-srgb", + "astc-10x8-unorm", + "astc-10x8-unorm-srgb", + "astc-10x10-unorm", + "astc-10x10-unorm-srgb", + "astc-12x10-unorm", + "astc-12x10-unorm-srgb", + "astc-12x12-unorm", + "astc-12x12-unorm-srgb" + ] : [] + ]; + return supportedGPUCompressedTextureFormats; + } + + "use strict"; + let supportedCompressedTextureFormats; + async function getSupportedCompressedTextureFormats() { + if (supportedCompressedTextureFormats !== void 0) + return supportedCompressedTextureFormats; + supportedCompressedTextureFormats = await (async () => { + const _isWebGPUSupported = await isWebGPUSupported(); + const _isWebGLSupported = isWebGLSupported(); + if (_isWebGPUSupported && _isWebGLSupported) { + const gpuTextureFormats = await getSupportedGPUCompressedTextureFormats(); + const glTextureFormats = getSupportedGlCompressedTextureFormats(); + return gpuTextureFormats.filter((format) => glTextureFormats.includes(format)); + } else if (_isWebGPUSupported) { + return await getSupportedGPUCompressedTextureFormats(); + } else if (_isWebGLSupported) { + return getSupportedGlCompressedTextureFormats(); + } + return []; + })(); + return supportedCompressedTextureFormats; + } + + "use strict"; + const nonCompressedFormats = [ + // 8-bit formats + "r8unorm", + "r8snorm", + "r8uint", + "r8sint", + // 16-bit formats + "r16uint", + "r16sint", + "r16float", + "rg8unorm", + "rg8snorm", + "rg8uint", + "rg8sint", + // 32-bit formats + "r32uint", + "r32sint", + "r32float", + "rg16uint", + "rg16sint", + "rg16float", + "rgba8unorm", + "rgba8unorm-srgb", + "rgba8snorm", + "rgba8uint", + "rgba8sint", + "bgra8unorm", + "bgra8unorm-srgb", + // Packed 32-bit formats + "rgb9e5ufloat", + "rgb10a2unorm", + "rg11b10ufloat", + // 64-bit formats + "rg32uint", + "rg32sint", + "rg32float", + "rgba16uint", + "rgba16sint", + "rgba16float", + // 128-bit formats + "rgba32uint", + "rgba32sint", + "rgba32float", + // Depth/stencil formats + "stencil8", + "depth16unorm", + "depth24plus", + "depth24plus-stencil8", + "depth32float", + // "depth32float-stencil8" feature + "depth32float-stencil8" + ]; + let supportedTextureFormats; + async function getSupportedTextureFormats() { + if (supportedTextureFormats !== void 0) + return supportedTextureFormats; + const compressedTextureFormats = await getSupportedCompressedTextureFormats(); + supportedTextureFormats = [ + ...nonCompressedFormats, + ...compressedTextureFormats + ]; + return supportedTextureFormats; + } + + const WORKER_CODE$1 = "(function () {\n 'use strict';\n\n function createLevelBuffers(basisTexture, basisTranscoderFormat) {\n const images = basisTexture.getNumImages();\n const levels = basisTexture.getNumLevels(0);\n const success = basisTexture.startTranscoding();\n if (!success) {\n throw new Error(\"startTranscoding failed\");\n }\n const levelBuffers = [];\n for (let levelIndex = 0; levelIndex < levels; ++levelIndex) {\n for (let sliceIndex = 0; sliceIndex < images; ++sliceIndex) {\n const transcodeSize = basisTexture.getImageTranscodedSizeInBytes(sliceIndex, levelIndex, basisTranscoderFormat);\n const levelBuffer = new Uint8Array(transcodeSize);\n const success2 = basisTexture.transcodeImage(levelBuffer, sliceIndex, levelIndex, basisTranscoderFormat, 1, 0);\n if (!success2) {\n throw new Error(\"transcodeImage failed\");\n }\n levelBuffers.push(levelBuffer);\n }\n }\n return levelBuffers;\n }\n\n const gpuFormatToBasisTranscoderFormatMap = {\n \"bc3-rgba-unorm\": 3,\n // cTFBC3_RGBA\n \"bc7-rgba-unorm\": 6,\n // cTFBC7_RGBA,\n \"etc2-rgba8unorm\": 1,\n // cTFETC2_RGBA,\n \"astc-4x4-unorm\": 10,\n // cTFASTC_4x4_RGBA,\n // Uncompressed\n rgba8unorm: 13,\n // cTFRGBA32,\n rgba4unorm: 16\n // cTFRGBA4444,\n };\n function gpuFormatToBasisTranscoderFormat(transcoderFormat) {\n const format = gpuFormatToBasisTranscoderFormatMap[transcoderFormat];\n if (format) {\n return format;\n }\n throw new Error(`Unsupported transcoderFormat: ${transcoderFormat}`);\n }\n\n const settings = {\n jsUrl: \"basis/basis_transcoder.js\",\n wasmUrl: \"basis/basis_transcoder.wasm\"\n };\n let basisTranscoderFormat;\n let basisTranscodedTextureFormat;\n let basisPromise;\n async function getBasis() {\n if (!basisPromise) {\n const absoluteJsUrl = new URL(settings.jsUrl, location.origin).href;\n const absoluteWasmUrl = new URL(settings.wasmUrl, location.origin).href;\n importScripts(absoluteJsUrl);\n basisPromise = new Promise((resolve) => {\n BASIS({\n locateFile: (_file) => absoluteWasmUrl\n }).then((module) => {\n module.initializeBasis();\n resolve(module.BasisFile);\n });\n });\n }\n return basisPromise;\n }\n async function fetchBasisTexture(url, BasisTexture) {\n const basisResponse = await fetch(url);\n if (basisResponse.ok) {\n const basisArrayBuffer = await basisResponse.arrayBuffer();\n return new BasisTexture(new Uint8Array(basisArrayBuffer));\n }\n throw new Error(`Failed to load Basis texture: ${url}`);\n }\n const preferredTranscodedFormat = [\n \"bc7-rgba-unorm\",\n \"astc-4x4-unorm\",\n \"etc2-rgba8unorm\",\n \"bc3-rgba-unorm\",\n \"rgba8unorm\"\n ];\n async function load(url) {\n const BasisTexture = await getBasis();\n const basisTexture = await fetchBasisTexture(url, BasisTexture);\n const levelBuffers = createLevelBuffers(basisTexture, basisTranscoderFormat);\n return {\n width: basisTexture.getImageWidth(0, 0),\n height: basisTexture.getImageHeight(0, 0),\n format: basisTranscodedTextureFormat,\n resource: levelBuffers,\n alphaMode: \"no-premultiply-alpha\"\n };\n }\n async function init(jsUrl, wasmUrl, supportedTextures) {\n if (jsUrl)\n settings.jsUrl = jsUrl;\n if (wasmUrl)\n settings.wasmUrl = wasmUrl;\n basisTranscodedTextureFormat = preferredTranscodedFormat.filter((format) => supportedTextures.includes(format))[0];\n basisTranscoderFormat = gpuFormatToBasisTranscoderFormat(basisTranscodedTextureFormat);\n await getBasis();\n }\n const messageHandlers = {\n init: async (data) => {\n const { jsUrl, wasmUrl, supportedTextures } = data;\n await init(jsUrl, wasmUrl, supportedTextures);\n },\n load: async (data) => {\n var _a;\n try {\n const textureOptions = await load(data.url);\n return {\n type: \"load\",\n url: data.url,\n success: true,\n textureOptions,\n transferables: (_a = textureOptions.resource) == null ? void 0 : _a.map((arr) => arr.buffer)\n };\n } catch (e) {\n throw e;\n }\n }\n };\n self.onmessage = async (messageEvent) => {\n const message = messageEvent.data;\n const response = await messageHandlers[message.type](message);\n if (response) {\n self.postMessage(response, response.transferables);\n }\n };\n\n})();\n"; + let WORKER_URL$1 = null; + let WorkerInstance$1 = class WorkerInstance + { + constructor() + { + if (!WORKER_URL$1) + { + WORKER_URL$1 = URL.createObjectURL(new Blob([WORKER_CODE$1], { type: 'application/javascript' })); + } + this.worker = new Worker(WORKER_URL$1); + } + }; + WorkerInstance$1.revokeObjectURL = function revokeObjectURL() + { + if (WORKER_URL$1) + { + URL.revokeObjectURL(WORKER_URL$1); + WORKER_URL$1 = null; + } + }; + + "use strict"; + const basisTranscoderUrls = { + jsUrl: "https://files.pixijs.download/transcoders/basis/basis_transcoder.js", + wasmUrl: "https://files.pixijs.download/transcoders/basis/basis_transcoder.wasm" + }; + function setBasisTranscoderPath(config) { + Object.assign(basisTranscoderUrls, config); + } + + "use strict"; + let basisWorker; + const urlHash$1 = {}; + function getBasisWorker(supportedTextures) { + if (!basisWorker) { + basisWorker = new WorkerInstance$1().worker; + basisWorker.onmessage = (messageEvent) => { + const { success, url, textureOptions } = messageEvent.data; + if (!success) { + console.warn("Failed to load Basis texture", url); + } + urlHash$1[url](textureOptions); + }; + basisWorker.postMessage({ + type: "init", + jsUrl: basisTranscoderUrls.jsUrl, + wasmUrl: basisTranscoderUrls.wasmUrl, + supportedTextures + }); + } + return basisWorker; + } + function loadBasisOnWorker(url, supportedTextures) { + const ktxWorker = getBasisWorker(supportedTextures); + return new Promise((resolve) => { + urlHash$1[url] = resolve; + ktxWorker.postMessage({ type: "load", url }); + }); + } + + "use strict"; + const loadBasis = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.High, + name: "loadBasis" + }, + name: "loadBasis", + test(url) { + return checkExtension(url, [".basis"]); + }, + async load(url, _asset, loader) { + const supportedTextures = await getSupportedTextureFormats(); + const textureOptions = await loadBasisOnWorker(url, supportedTextures); + const compressedTextureSource = new CompressedSource(textureOptions); + return createTexture(compressedTextureSource, loader, url); + }, + unload(texture) { + if (Array.isArray(texture)) { + texture.forEach((t) => t.destroy(true)); + } else { + texture.destroy(true); + } + } + }; + + "use strict"; + + "use strict"; + function createLevelBuffers(basisTexture, basisTranscoderFormat) { + const images = basisTexture.getNumImages(); + const levels = basisTexture.getNumLevels(0); + const success = basisTexture.startTranscoding(); + if (!success) { + throw new Error("startTranscoding failed"); + } + const levelBuffers = []; + for (let levelIndex = 0; levelIndex < levels; ++levelIndex) { + for (let sliceIndex = 0; sliceIndex < images; ++sliceIndex) { + const transcodeSize = basisTexture.getImageTranscodedSizeInBytes(sliceIndex, levelIndex, basisTranscoderFormat); + const levelBuffer = new Uint8Array(transcodeSize); + const success2 = basisTexture.transcodeImage(levelBuffer, sliceIndex, levelIndex, basisTranscoderFormat, 1, 0); + if (!success2) { + throw new Error("transcodeImage failed"); + } + levelBuffers.push(levelBuffer); + } + } + return levelBuffers; + } + + "use strict"; + const gpuFormatToBasisTranscoderFormatMap$1 = { + "bc3-rgba-unorm": 3, + // cTFBC3_RGBA + "bc7-rgba-unorm": 6, + // cTFBC7_RGBA, + "etc2-rgba8unorm": 1, + // cTFETC2_RGBA, + "astc-4x4-unorm": 10, + // cTFASTC_4x4_RGBA, + // Uncompressed + rgba8unorm: 13, + // cTFRGBA32, + rgba4unorm: 16 + // cTFRGBA4444, + }; + function gpuFormatToBasisTranscoderFormat(transcoderFormat) { + const format = gpuFormatToBasisTranscoderFormatMap$1[transcoderFormat]; + if (format) { + return format; + } + throw new Error(`Unsupported transcoderFormat: ${transcoderFormat}`); + } + + "use strict"; + const DDS_HEADER_FIELDS = { + MAGIC: 0, + SIZE: 1, + FLAGS: 2, + HEIGHT: 3, + WIDTH: 4, + MIPMAP_COUNT: 7, + PIXEL_FORMAT: 19, + PF_FLAGS: 20, + FOURCC: 21, + RGB_BITCOUNT: 22, + R_BIT_MASK: 23, + G_BIT_MASK: 24, + B_BIT_MASK: 25, + A_BIT_MASK: 26 + }; + const DDS_DX10_FIELDS = { + DXGI_FORMAT: 0, + RESOURCE_DIMENSION: 1, + MISC_FLAG: 2, + ARRAY_SIZE: 3, + MISC_FLAGS2: 4 + }; + var DXGI_FORMAT = /* @__PURE__ */ ((DXGI_FORMAT2) => { + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_UNKNOWN"] = 0] = "DXGI_FORMAT_UNKNOWN"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32A32_TYPELESS"] = 1] = "DXGI_FORMAT_R32G32B32A32_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32A32_FLOAT"] = 2] = "DXGI_FORMAT_R32G32B32A32_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32A32_UINT"] = 3] = "DXGI_FORMAT_R32G32B32A32_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32A32_SINT"] = 4] = "DXGI_FORMAT_R32G32B32A32_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32_TYPELESS"] = 5] = "DXGI_FORMAT_R32G32B32_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32_FLOAT"] = 6] = "DXGI_FORMAT_R32G32B32_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32_UINT"] = 7] = "DXGI_FORMAT_R32G32B32_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32B32_SINT"] = 8] = "DXGI_FORMAT_R32G32B32_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_TYPELESS"] = 9] = "DXGI_FORMAT_R16G16B16A16_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_FLOAT"] = 10] = "DXGI_FORMAT_R16G16B16A16_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_UNORM"] = 11] = "DXGI_FORMAT_R16G16B16A16_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_UINT"] = 12] = "DXGI_FORMAT_R16G16B16A16_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_SNORM"] = 13] = "DXGI_FORMAT_R16G16B16A16_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16B16A16_SINT"] = 14] = "DXGI_FORMAT_R16G16B16A16_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32_TYPELESS"] = 15] = "DXGI_FORMAT_R32G32_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32_FLOAT"] = 16] = "DXGI_FORMAT_R32G32_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32_UINT"] = 17] = "DXGI_FORMAT_R32G32_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G32_SINT"] = 18] = "DXGI_FORMAT_R32G32_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32G8X24_TYPELESS"] = 19] = "DXGI_FORMAT_R32G8X24_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_D32_FLOAT_S8X24_UINT"] = 20] = "DXGI_FORMAT_D32_FLOAT_S8X24_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS"] = 21] = "DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_X32_TYPELESS_G8X24_UINT"] = 22] = "DXGI_FORMAT_X32_TYPELESS_G8X24_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R10G10B10A2_TYPELESS"] = 23] = "DXGI_FORMAT_R10G10B10A2_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R10G10B10A2_UNORM"] = 24] = "DXGI_FORMAT_R10G10B10A2_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R10G10B10A2_UINT"] = 25] = "DXGI_FORMAT_R10G10B10A2_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R11G11B10_FLOAT"] = 26] = "DXGI_FORMAT_R11G11B10_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_TYPELESS"] = 27] = "DXGI_FORMAT_R8G8B8A8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_UNORM"] = 28] = "DXGI_FORMAT_R8G8B8A8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_UNORM_SRGB"] = 29] = "DXGI_FORMAT_R8G8B8A8_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_UINT"] = 30] = "DXGI_FORMAT_R8G8B8A8_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_SNORM"] = 31] = "DXGI_FORMAT_R8G8B8A8_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8B8A8_SINT"] = 32] = "DXGI_FORMAT_R8G8B8A8_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_TYPELESS"] = 33] = "DXGI_FORMAT_R16G16_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_FLOAT"] = 34] = "DXGI_FORMAT_R16G16_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_UNORM"] = 35] = "DXGI_FORMAT_R16G16_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_UINT"] = 36] = "DXGI_FORMAT_R16G16_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_SNORM"] = 37] = "DXGI_FORMAT_R16G16_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16G16_SINT"] = 38] = "DXGI_FORMAT_R16G16_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32_TYPELESS"] = 39] = "DXGI_FORMAT_R32_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_D32_FLOAT"] = 40] = "DXGI_FORMAT_D32_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32_FLOAT"] = 41] = "DXGI_FORMAT_R32_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32_UINT"] = 42] = "DXGI_FORMAT_R32_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R32_SINT"] = 43] = "DXGI_FORMAT_R32_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R24G8_TYPELESS"] = 44] = "DXGI_FORMAT_R24G8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_D24_UNORM_S8_UINT"] = 45] = "DXGI_FORMAT_D24_UNORM_S8_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R24_UNORM_X8_TYPELESS"] = 46] = "DXGI_FORMAT_R24_UNORM_X8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_X24_TYPELESS_G8_UINT"] = 47] = "DXGI_FORMAT_X24_TYPELESS_G8_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_TYPELESS"] = 48] = "DXGI_FORMAT_R8G8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_UNORM"] = 49] = "DXGI_FORMAT_R8G8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_UINT"] = 50] = "DXGI_FORMAT_R8G8_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_SNORM"] = 51] = "DXGI_FORMAT_R8G8_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_SINT"] = 52] = "DXGI_FORMAT_R8G8_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_TYPELESS"] = 53] = "DXGI_FORMAT_R16_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_FLOAT"] = 54] = "DXGI_FORMAT_R16_FLOAT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_D16_UNORM"] = 55] = "DXGI_FORMAT_D16_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_UNORM"] = 56] = "DXGI_FORMAT_R16_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_UINT"] = 57] = "DXGI_FORMAT_R16_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_SNORM"] = 58] = "DXGI_FORMAT_R16_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R16_SINT"] = 59] = "DXGI_FORMAT_R16_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8_TYPELESS"] = 60] = "DXGI_FORMAT_R8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8_UNORM"] = 61] = "DXGI_FORMAT_R8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8_UINT"] = 62] = "DXGI_FORMAT_R8_UINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8_SNORM"] = 63] = "DXGI_FORMAT_R8_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8_SINT"] = 64] = "DXGI_FORMAT_R8_SINT"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_A8_UNORM"] = 65] = "DXGI_FORMAT_A8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R1_UNORM"] = 66] = "DXGI_FORMAT_R1_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R9G9B9E5_SHAREDEXP"] = 67] = "DXGI_FORMAT_R9G9B9E5_SHAREDEXP"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R8G8_B8G8_UNORM"] = 68] = "DXGI_FORMAT_R8G8_B8G8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_G8R8_G8B8_UNORM"] = 69] = "DXGI_FORMAT_G8R8_G8B8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC1_TYPELESS"] = 70] = "DXGI_FORMAT_BC1_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC1_UNORM"] = 71] = "DXGI_FORMAT_BC1_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC1_UNORM_SRGB"] = 72] = "DXGI_FORMAT_BC1_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC2_TYPELESS"] = 73] = "DXGI_FORMAT_BC2_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC2_UNORM"] = 74] = "DXGI_FORMAT_BC2_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC2_UNORM_SRGB"] = 75] = "DXGI_FORMAT_BC2_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC3_TYPELESS"] = 76] = "DXGI_FORMAT_BC3_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC3_UNORM"] = 77] = "DXGI_FORMAT_BC3_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC3_UNORM_SRGB"] = 78] = "DXGI_FORMAT_BC3_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC4_TYPELESS"] = 79] = "DXGI_FORMAT_BC4_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC4_UNORM"] = 80] = "DXGI_FORMAT_BC4_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC4_SNORM"] = 81] = "DXGI_FORMAT_BC4_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC5_TYPELESS"] = 82] = "DXGI_FORMAT_BC5_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC5_UNORM"] = 83] = "DXGI_FORMAT_BC5_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC5_SNORM"] = 84] = "DXGI_FORMAT_BC5_SNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B5G6R5_UNORM"] = 85] = "DXGI_FORMAT_B5G6R5_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B5G5R5A1_UNORM"] = 86] = "DXGI_FORMAT_B5G5R5A1_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8A8_UNORM"] = 87] = "DXGI_FORMAT_B8G8R8A8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8X8_UNORM"] = 88] = "DXGI_FORMAT_B8G8R8X8_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM"] = 89] = "DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8A8_TYPELESS"] = 90] = "DXGI_FORMAT_B8G8R8A8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8A8_UNORM_SRGB"] = 91] = "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8X8_TYPELESS"] = 92] = "DXGI_FORMAT_B8G8R8X8_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B8G8R8X8_UNORM_SRGB"] = 93] = "DXGI_FORMAT_B8G8R8X8_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC6H_TYPELESS"] = 94] = "DXGI_FORMAT_BC6H_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC6H_UF16"] = 95] = "DXGI_FORMAT_BC6H_UF16"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC6H_SF16"] = 96] = "DXGI_FORMAT_BC6H_SF16"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC7_TYPELESS"] = 97] = "DXGI_FORMAT_BC7_TYPELESS"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC7_UNORM"] = 98] = "DXGI_FORMAT_BC7_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_BC7_UNORM_SRGB"] = 99] = "DXGI_FORMAT_BC7_UNORM_SRGB"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_AYUV"] = 100] = "DXGI_FORMAT_AYUV"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_Y410"] = 101] = "DXGI_FORMAT_Y410"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_Y416"] = 102] = "DXGI_FORMAT_Y416"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_NV12"] = 103] = "DXGI_FORMAT_NV12"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_P010"] = 104] = "DXGI_FORMAT_P010"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_P016"] = 105] = "DXGI_FORMAT_P016"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_420_OPAQUE"] = 106] = "DXGI_FORMAT_420_OPAQUE"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_YUY2"] = 107] = "DXGI_FORMAT_YUY2"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_Y210"] = 108] = "DXGI_FORMAT_Y210"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_Y216"] = 109] = "DXGI_FORMAT_Y216"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_NV11"] = 110] = "DXGI_FORMAT_NV11"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_AI44"] = 111] = "DXGI_FORMAT_AI44"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_IA44"] = 112] = "DXGI_FORMAT_IA44"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_P8"] = 113] = "DXGI_FORMAT_P8"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_A8P8"] = 114] = "DXGI_FORMAT_A8P8"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_B4G4R4A4_UNORM"] = 115] = "DXGI_FORMAT_B4G4R4A4_UNORM"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_P208"] = 116] = "DXGI_FORMAT_P208"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_V208"] = 117] = "DXGI_FORMAT_V208"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_V408"] = 118] = "DXGI_FORMAT_V408"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE"] = 119] = "DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE"] = 120] = "DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE"; + DXGI_FORMAT2[DXGI_FORMAT2["DXGI_FORMAT_FORCE_UINT"] = 121] = "DXGI_FORMAT_FORCE_UINT"; + return DXGI_FORMAT2; + })(DXGI_FORMAT || {}); + var D3D10_RESOURCE_DIMENSION = /* @__PURE__ */ ((D3D10_RESOURCE_DIMENSION2) => { + D3D10_RESOURCE_DIMENSION2[D3D10_RESOURCE_DIMENSION2["DDS_DIMENSION_TEXTURE1D"] = 2] = "DDS_DIMENSION_TEXTURE1D"; + D3D10_RESOURCE_DIMENSION2[D3D10_RESOURCE_DIMENSION2["DDS_DIMENSION_TEXTURE2D"] = 3] = "DDS_DIMENSION_TEXTURE2D"; + D3D10_RESOURCE_DIMENSION2[D3D10_RESOURCE_DIMENSION2["DDS_DIMENSION_TEXTURE3D"] = 6] = "DDS_DIMENSION_TEXTURE3D"; + return D3D10_RESOURCE_DIMENSION2; + })(D3D10_RESOURCE_DIMENSION || {}); + function fourCCToInt32(value) { + return value.charCodeAt(0) + (value.charCodeAt(1) << 8) + (value.charCodeAt(2) << 16) + (value.charCodeAt(3) << 24); + } + var D3DFMT = ((D3DFMT2) => { + D3DFMT2[D3DFMT2["UNKNOWN"] = 0] = "UNKNOWN"; + D3DFMT2[D3DFMT2["R8G8B8"] = 20] = "R8G8B8"; + D3DFMT2[D3DFMT2["A8R8G8B8"] = 21] = "A8R8G8B8"; + D3DFMT2[D3DFMT2["X8R8G8B8"] = 22] = "X8R8G8B8"; + D3DFMT2[D3DFMT2["R5G6B5"] = 23] = "R5G6B5"; + D3DFMT2[D3DFMT2["X1R5G5B5"] = 24] = "X1R5G5B5"; + D3DFMT2[D3DFMT2["A1R5G5B5"] = 25] = "A1R5G5B5"; + D3DFMT2[D3DFMT2["A4R4G4B4"] = 26] = "A4R4G4B4"; + D3DFMT2[D3DFMT2["R3G3B2"] = 27] = "R3G3B2"; + D3DFMT2[D3DFMT2["A8"] = 28] = "A8"; + D3DFMT2[D3DFMT2["A8R3G3B2"] = 29] = "A8R3G3B2"; + D3DFMT2[D3DFMT2["X4R4G4B4"] = 30] = "X4R4G4B4"; + D3DFMT2[D3DFMT2["A2B10G10R10"] = 31] = "A2B10G10R10"; + D3DFMT2[D3DFMT2["A8B8G8R8"] = 32] = "A8B8G8R8"; + D3DFMT2[D3DFMT2["X8B8G8R8"] = 33] = "X8B8G8R8"; + D3DFMT2[D3DFMT2["G16R16"] = 34] = "G16R16"; + D3DFMT2[D3DFMT2["A2R10G10B10"] = 35] = "A2R10G10B10"; + D3DFMT2[D3DFMT2["A16B16G16R16"] = 36] = "A16B16G16R16"; + D3DFMT2[D3DFMT2["A8P8"] = 40] = "A8P8"; + D3DFMT2[D3DFMT2["P8"] = 41] = "P8"; + D3DFMT2[D3DFMT2["L8"] = 50] = "L8"; + D3DFMT2[D3DFMT2["A8L8"] = 51] = "A8L8"; + D3DFMT2[D3DFMT2["A4L4"] = 52] = "A4L4"; + D3DFMT2[D3DFMT2["V8U8"] = 60] = "V8U8"; + D3DFMT2[D3DFMT2["L6V5U5"] = 61] = "L6V5U5"; + D3DFMT2[D3DFMT2["X8L8V8U8"] = 62] = "X8L8V8U8"; + D3DFMT2[D3DFMT2["Q8W8V8U8"] = 63] = "Q8W8V8U8"; + D3DFMT2[D3DFMT2["V16U16"] = 64] = "V16U16"; + D3DFMT2[D3DFMT2["A2W10V10U10"] = 67] = "A2W10V10U10"; + D3DFMT2[D3DFMT2["Q16W16V16U16"] = 110] = "Q16W16V16U16"; + D3DFMT2[D3DFMT2["R16F"] = 111] = "R16F"; + D3DFMT2[D3DFMT2["G16R16F"] = 112] = "G16R16F"; + D3DFMT2[D3DFMT2["A16B16G16R16F"] = 113] = "A16B16G16R16F"; + D3DFMT2[D3DFMT2["R32F"] = 114] = "R32F"; + D3DFMT2[D3DFMT2["G32R32F"] = 115] = "G32R32F"; + D3DFMT2[D3DFMT2["A32B32G32R32F"] = 116] = "A32B32G32R32F"; + D3DFMT2[D3DFMT2["UYVY"] = fourCCToInt32("UYVY")] = "UYVY"; + D3DFMT2[D3DFMT2["R8G8_B8G8"] = fourCCToInt32("RGBG")] = "R8G8_B8G8"; + D3DFMT2[D3DFMT2["YUY2"] = fourCCToInt32("YUY2")] = "YUY2"; + D3DFMT2[D3DFMT2["D3DFMT_G8R8_G8B8"] = fourCCToInt32("GRGB")] = "D3DFMT_G8R8_G8B8"; + D3DFMT2[D3DFMT2["DXT1"] = fourCCToInt32("DXT1")] = "DXT1"; + D3DFMT2[D3DFMT2["DXT2"] = fourCCToInt32("DXT2")] = "DXT2"; + D3DFMT2[D3DFMT2["DXT3"] = fourCCToInt32("DXT3")] = "DXT3"; + D3DFMT2[D3DFMT2["DXT4"] = fourCCToInt32("DXT4")] = "DXT4"; + D3DFMT2[D3DFMT2["DXT5"] = fourCCToInt32("DXT5")] = "DXT5"; + D3DFMT2[D3DFMT2["ATI1"] = fourCCToInt32("ATI1")] = "ATI1"; + D3DFMT2[D3DFMT2["AT1N"] = fourCCToInt32("AT1N")] = "AT1N"; + D3DFMT2[D3DFMT2["ATI2"] = fourCCToInt32("ATI2")] = "ATI2"; + D3DFMT2[D3DFMT2["AT2N"] = fourCCToInt32("AT2N")] = "AT2N"; + D3DFMT2[D3DFMT2["BC4U"] = fourCCToInt32("BC4U")] = "BC4U"; + D3DFMT2[D3DFMT2["BC4S"] = fourCCToInt32("BC4S")] = "BC4S"; + D3DFMT2[D3DFMT2["BC5U"] = fourCCToInt32("BC5U")] = "BC5U"; + D3DFMT2[D3DFMT2["BC5S"] = fourCCToInt32("BC5S")] = "BC5S"; + D3DFMT2[D3DFMT2["DX10"] = fourCCToInt32("DX10")] = "DX10"; + return D3DFMT2; + })(D3DFMT || {}); + const FOURCC_TO_TEXTURE_FORMAT = { + [D3DFMT.DXT1]: "bc1-rgba-unorm", + [D3DFMT.DXT2]: "bc2-rgba-unorm", + [D3DFMT.DXT3]: "bc2-rgba-unorm", + [D3DFMT.DXT4]: "bc3-rgba-unorm", + [D3DFMT.DXT5]: "bc3-rgba-unorm", + [D3DFMT.ATI1]: "bc4-r-unorm", + [D3DFMT.BC4U]: "bc4-r-unorm", + [D3DFMT.BC4S]: "bc4-r-snorm", + [D3DFMT.ATI2]: "bc5-rg-unorm", + [D3DFMT.BC5U]: "bc5-rg-unorm", + [D3DFMT.BC5S]: "bc5-rg-snorm", + [36 /* A16B16G16R16 */]: "rgba16uint", + [110 /* Q16W16V16U16 */]: "rgba16sint", + [111 /* R16F */]: "r16float", + [112 /* G16R16F */]: "rg16float", + [113 /* A16B16G16R16F */]: "rgba16float", + [114 /* R32F */]: "r32float", + [115 /* G32R32F */]: "rg32float", + [116 /* A32B32G32R32F */]: "rgba32float" + }; + const DXGI_TO_TEXTURE_FORMAT = { + [70 /* DXGI_FORMAT_BC1_TYPELESS */]: "bc1-rgba-unorm", + [71 /* DXGI_FORMAT_BC1_UNORM */]: "bc1-rgba-unorm", + [72 /* DXGI_FORMAT_BC1_UNORM_SRGB */]: "bc1-rgba-unorm-srgb", + [73 /* DXGI_FORMAT_BC2_TYPELESS */]: "bc2-rgba-unorm", + [74 /* DXGI_FORMAT_BC2_UNORM */]: "bc2-rgba-unorm", + [75 /* DXGI_FORMAT_BC2_UNORM_SRGB */]: "bc2-rgba-unorm-srgb", + [76 /* DXGI_FORMAT_BC3_TYPELESS */]: "bc3-rgba-unorm", + [77 /* DXGI_FORMAT_BC3_UNORM */]: "bc3-rgba-unorm", + [78 /* DXGI_FORMAT_BC3_UNORM_SRGB */]: "bc3-rgba-unorm-srgb", + [79 /* DXGI_FORMAT_BC4_TYPELESS */]: "bc4-r-unorm", + [80 /* DXGI_FORMAT_BC4_UNORM */]: "bc4-r-unorm", + [81 /* DXGI_FORMAT_BC4_SNORM */]: "bc4-r-snorm", + [82 /* DXGI_FORMAT_BC5_TYPELESS */]: "bc5-rg-unorm", + [83 /* DXGI_FORMAT_BC5_UNORM */]: "bc5-rg-unorm", + [84 /* DXGI_FORMAT_BC5_SNORM */]: "bc5-rg-snorm", + [94 /* DXGI_FORMAT_BC6H_TYPELESS */]: "bc6h-rgb-ufloat", + [95 /* DXGI_FORMAT_BC6H_UF16 */]: "bc6h-rgb-ufloat", + [96 /* DXGI_FORMAT_BC6H_SF16 */]: "bc6h-rgb-float", + [97 /* DXGI_FORMAT_BC7_TYPELESS */]: "bc7-rgba-unorm", + [98 /* DXGI_FORMAT_BC7_UNORM */]: "bc7-rgba-unorm", + [99 /* DXGI_FORMAT_BC7_UNORM_SRGB */]: "bc7-rgba-unorm-srgb", + [28 /* DXGI_FORMAT_R8G8B8A8_UNORM */]: "rgba8unorm", + [29 /* DXGI_FORMAT_R8G8B8A8_UNORM_SRGB */]: "rgba8unorm-srgb", + [87 /* DXGI_FORMAT_B8G8R8A8_UNORM */]: "bgra8unorm", + [91 /* DXGI_FORMAT_B8G8R8A8_UNORM_SRGB */]: "bgra8unorm-srgb", + [41 /* DXGI_FORMAT_R32_FLOAT */]: "r32float", + [49 /* DXGI_FORMAT_R8G8_UNORM */]: "rg8unorm", + [56 /* DXGI_FORMAT_R16_UNORM */]: "r16uint", + [61 /* DXGI_FORMAT_R8_UNORM */]: "r8unorm", + [24 /* DXGI_FORMAT_R10G10B10A2_UNORM */]: "rgb10a2unorm", + [11 /* DXGI_FORMAT_R16G16B16A16_UNORM */]: "rgba16uint", + [13 /* DXGI_FORMAT_R16G16B16A16_SNORM */]: "rgba16sint", + [10 /* DXGI_FORMAT_R16G16B16A16_FLOAT */]: "rgba16float", + [54 /* DXGI_FORMAT_R16_FLOAT */]: "r16float", + [34 /* DXGI_FORMAT_R16G16_FLOAT */]: "rg16float", + [16 /* DXGI_FORMAT_R32G32_FLOAT */]: "rg32float", + [2 /* DXGI_FORMAT_R32G32B32A32_FLOAT */]: "rgba32float" + }; + const DDS = { + MAGIC_VALUE: 542327876, + MAGIC_SIZE: 4, + HEADER_SIZE: 124, + HEADER_DX10_SIZE: 20, + PIXEL_FORMAT_FLAGS: { + // PIXEL_FORMAT flags + // https://github.com/Microsoft/DirectXTex/blob/main/DirectXTex/DDS.h + // https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-pixelformat + ALPHAPIXELS: 1, + ALPHA: 2, + FOURCC: 4, + RGB: 64, + RGBA: 65, + YUV: 512, + LUMINANCE: 131072, + LUMINANCEA: 131073 + }, + RESOURCE_MISC_TEXTURECUBE: 4, + HEADER_FIELDS: DDS_HEADER_FIELDS, + HEADER_DX10_FIELDS: DDS_DX10_FIELDS, + DXGI_FORMAT, + D3D10_RESOURCE_DIMENSION, + D3DFMT + }; + const TEXTURE_FORMAT_BLOCK_SIZE = { + "bc1-rgba-unorm": 8, + "bc1-rgba-unorm-srgb": 8, + "bc2-rgba-unorm": 16, + "bc2-rgba-unorm-srgb": 16, + "bc3-rgba-unorm": 16, + "bc3-rgba-unorm-srgb": 16, + "bc4-r-unorm": 8, + "bc4-r-snorm": 8, + "bc5-rg-unorm": 16, + "bc5-rg-snorm": 16, + "bc6h-rgb-ufloat": 16, + "bc6h-rgb-float": 16, + "bc7-rgba-unorm": 16, + "bc7-rgba-unorm-srgb": 16 + }; + + "use strict"; + function parseDDS(arrayBuffer, supportedFormats) { + const { + format, + fourCC, + width, + height, + dataOffset, + mipmapCount + } = parseDDSHeader(arrayBuffer); + if (!supportedFormats.includes(format)) { + throw new Error(`Unsupported texture format: ${fourCC} ${format}, supported: ${supportedFormats}`); + } + if (mipmapCount <= 1) { + return { + format, + width, + height, + resource: [new Uint8Array(arrayBuffer, dataOffset)], + alphaMode: "no-premultiply-alpha" + }; + } + const levelBuffers = getMipmapLevelBuffers(format, width, height, dataOffset, mipmapCount, arrayBuffer); + const textureOptions = { + format, + width, + height, + resource: levelBuffers, + alphaMode: "no-premultiply-alpha" + }; + return textureOptions; + } + function getMipmapLevelBuffers(format, width, height, dataOffset, mipmapCount, arrayBuffer) { + const levelBuffers = []; + const blockBytes = TEXTURE_FORMAT_BLOCK_SIZE[format]; + let mipWidth = width; + let mipHeight = height; + let offset = dataOffset; + for (let level = 0; level < mipmapCount; ++level) { + const byteLength = blockBytes ? Math.max(4, mipWidth) / 4 * Math.max(4, mipHeight) / 4 * blockBytes : mipWidth * mipHeight * 4; + const levelBuffer = new Uint8Array(arrayBuffer, offset, byteLength); + levelBuffers.push(levelBuffer); + offset += byteLength; + mipWidth = Math.max(mipWidth >> 1, 1); + mipHeight = Math.max(mipHeight >> 1, 1); + } + return levelBuffers; + } + function parseDDSHeader(buffer) { + const header = new Uint32Array(buffer, 0, DDS.HEADER_SIZE / Uint32Array.BYTES_PER_ELEMENT); + if (header[DDS.HEADER_FIELDS.MAGIC] !== DDS.MAGIC_VALUE) { + throw new Error("Invalid magic number in DDS header"); + } + const height = header[DDS.HEADER_FIELDS.HEIGHT]; + const width = header[DDS.HEADER_FIELDS.WIDTH]; + const mipmapCount = Math.max(1, header[DDS.HEADER_FIELDS.MIPMAP_COUNT]); + const flags = header[DDS.HEADER_FIELDS.PF_FLAGS]; + const fourCC = header[DDS.HEADER_FIELDS.FOURCC]; + const format = getTextureFormat(header, flags, fourCC, buffer); + const dataOffset = DDS.MAGIC_SIZE + DDS.HEADER_SIZE + (fourCC === DDS.D3DFMT.DX10 ? DDS.HEADER_DX10_SIZE : 0); + return { + format, + fourCC, + width, + height, + dataOffset, + mipmapCount + }; + } + function getTextureFormat(header, flags, fourCC, buffer) { + if (flags & DDS.PIXEL_FORMAT_FLAGS.FOURCC) { + if (fourCC === DDS.D3DFMT.DX10) { + const dx10Header = new Uint32Array( + buffer, + DDS.MAGIC_SIZE + DDS.HEADER_SIZE, + // there is a 20-byte DDS_HEADER_DX10 after DDS_HEADER + DDS.HEADER_DX10_SIZE / Uint32Array.BYTES_PER_ELEMENT + ); + const miscFlag = dx10Header[DDS.HEADER_DX10_FIELDS.MISC_FLAG]; + if (miscFlag === DDS.RESOURCE_MISC_TEXTURECUBE) { + throw new Error("DDSParser does not support cubemap textures"); + } + const resourceDimension = dx10Header[DDS.HEADER_DX10_FIELDS.RESOURCE_DIMENSION]; + if (resourceDimension === DDS.D3D10_RESOURCE_DIMENSION.DDS_DIMENSION_TEXTURE3D) { + throw new Error("DDSParser does not supported 3D texture data"); + } + const dxgiFormat = dx10Header[DDS.HEADER_DX10_FIELDS.DXGI_FORMAT]; + if (dxgiFormat in DXGI_TO_TEXTURE_FORMAT) { + return DXGI_TO_TEXTURE_FORMAT[dxgiFormat]; + } + throw new Error(`DDSParser cannot parse texture data with DXGI format ${dxgiFormat}`); + } + if (fourCC in FOURCC_TO_TEXTURE_FORMAT) { + return FOURCC_TO_TEXTURE_FORMAT[fourCC]; + } + throw new Error(`DDSParser cannot parse texture data with fourCC format ${fourCC}`); + } + if (flags & DDS.PIXEL_FORMAT_FLAGS.RGB || flags & DDS.PIXEL_FORMAT_FLAGS.RGBA) { + return getUncompressedTextureFormat(header); + } + if (flags & DDS.PIXEL_FORMAT_FLAGS.YUV) { + throw new Error("DDSParser does not supported YUV uncompressed texture data."); + } + if (flags & DDS.PIXEL_FORMAT_FLAGS.LUMINANCE || flags & DDS.PIXEL_FORMAT_FLAGS.LUMINANCEA) { + throw new Error("DDSParser does not support single-channel (lumninance) texture data!"); + } + if (flags & DDS.PIXEL_FORMAT_FLAGS.ALPHA || flags & DDS.PIXEL_FORMAT_FLAGS.ALPHAPIXELS) { + throw new Error("DDSParser does not support single-channel (alpha) texture data!"); + } + throw new Error("DDSParser failed to load a texture file due to an unknown reason!"); + } + function getUncompressedTextureFormat(header) { + const bitCount = header[DDS.HEADER_FIELDS.RGB_BITCOUNT]; + const rBitMask = header[DDS.HEADER_FIELDS.R_BIT_MASK]; + const gBitMask = header[DDS.HEADER_FIELDS.G_BIT_MASK]; + const bBitMask = header[DDS.HEADER_FIELDS.B_BIT_MASK]; + const aBitMask = header[DDS.HEADER_FIELDS.A_BIT_MASK]; + switch (bitCount) { + case 32: + if (rBitMask === 255 && gBitMask === 65280 && bBitMask === 16711680 && aBitMask === 4278190080) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM]; + } + if (rBitMask === 16711680 && gBitMask === 65280 && bBitMask === 255 && aBitMask === 4278190080) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM]; + } + if (rBitMask === 1072693248 && gBitMask === 1047552 && bBitMask === 1023 && aBitMask === 3221225472) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R10G10B10A2_UNORM]; + } + if (rBitMask === 65535 && gBitMask === 4294901760 && bBitMask === 0 && aBitMask === 0) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R16G16_UNORM]; + } + if (rBitMask === 4294967295 && gBitMask === 0 && bBitMask === 0 && aBitMask === 0) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R32_FLOAT]; + } + break; + case 24: + if (rBitMask === 16711680 && gBitMask === 65280 && bBitMask === 255 && aBitMask === 32768) { + } + break; + case 16: + if (rBitMask === 31744 && gBitMask === 992 && bBitMask === 31 && aBitMask === 32768) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM]; + } + if (rBitMask === 63488 && gBitMask === 2016 && bBitMask === 31 && aBitMask === 0) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_B5G6R5_UNORM]; + } + if (rBitMask === 3840 && gBitMask === 240 && bBitMask === 15 && aBitMask === 61440) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_B4G4R4A4_UNORM]; + } + if (rBitMask === 255 && gBitMask === 0 && bBitMask === 0 && aBitMask === 65280) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R8G8_UNORM]; + } + if (rBitMask === 65535 && gBitMask === 0 && bBitMask === 0 && aBitMask === 0) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R16_UNORM]; + } + break; + case 8: + if (rBitMask === 255 && gBitMask === 0 && bBitMask === 0 && aBitMask === 0) { + return DXGI_TO_TEXTURE_FORMAT[DDS.DXGI_FORMAT.DXGI_FORMAT_R8_UNORM]; + } + break; + } + throw new Error(`DDSParser does not support uncompressed texture with configuration: + bitCount = ${bitCount}, rBitMask = ${rBitMask}, gBitMask = ${gBitMask}, aBitMask = ${aBitMask}`); + } + + "use strict"; + const loadDDS = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.High, + name: "loadDDS" + }, + name: "loadDDS", + test(url) { + return checkExtension(url, [".dds"]); + }, + async load(url, _asset, loader) { + const supportedTextures = await getSupportedTextureFormats(); + const ddsResponse = await fetch(url); + const ddsArrayBuffer = await ddsResponse.arrayBuffer(); + const textureOptions = parseDDS(ddsArrayBuffer, supportedTextures); + const compressedTextureSource = new CompressedSource(textureOptions); + return createTexture(compressedTextureSource, loader, url); + }, + unload(texture) { + if (Array.isArray(texture)) { + texture.forEach((t) => t.destroy(true)); + } else { + texture.destroy(true); + } + } + }; + + "use strict"; + var GL_INTERNAL_FORMAT = /* @__PURE__ */ ((GL_INTERNAL_FORMAT2) => { + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["RGBA8_SNORM"] = 36759] = "RGBA8_SNORM"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["RGBA"] = 6408] = "RGBA"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["RGBA8UI"] = 36220] = "RGBA8UI"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["SRGB8_ALPHA8"] = 35907] = "SRGB8_ALPHA8"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["RGBA8I"] = 36238] = "RGBA8I"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["RGBA8"] = 32856] = "RGBA8"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGB_S3TC_DXT1_EXT"] = 33776] = "COMPRESSED_RGB_S3TC_DXT1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_S3TC_DXT1_EXT"] = 33777] = "COMPRESSED_RGBA_S3TC_DXT1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_S3TC_DXT3_EXT"] = 33778] = "COMPRESSED_RGBA_S3TC_DXT3_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_S3TC_DXT5_EXT"] = 33779] = "COMPRESSED_RGBA_S3TC_DXT5_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT"] = 35917] = "COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT"] = 35918] = "COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT"] = 35919] = "COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB_S3TC_DXT1_EXT"] = 35916] = "COMPRESSED_SRGB_S3TC_DXT1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RED_RGTC1_EXT"] = 36283] = "COMPRESSED_RED_RGTC1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SIGNED_RED_RGTC1_EXT"] = 36284] = "COMPRESSED_SIGNED_RED_RGTC1_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RED_GREEN_RGTC2_EXT"] = 36285] = "COMPRESSED_RED_GREEN_RGTC2_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT"] = 36286] = "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_R11_EAC"] = 37488] = "COMPRESSED_R11_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SIGNED_R11_EAC"] = 37489] = "COMPRESSED_SIGNED_R11_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RG11_EAC"] = 37490] = "COMPRESSED_RG11_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SIGNED_RG11_EAC"] = 37491] = "COMPRESSED_SIGNED_RG11_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGB8_ETC2"] = 37492] = "COMPRESSED_RGB8_ETC2"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA8_ETC2_EAC"] = 37496] = "COMPRESSED_RGBA8_ETC2_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ETC2"] = 37493] = "COMPRESSED_SRGB8_ETC2"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"] = 37497] = "COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"] = 37494] = "COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"] = 37495] = "COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_4x4_KHR"] = 37808] = "COMPRESSED_RGBA_ASTC_4x4_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_5x4_KHR"] = 37809] = "COMPRESSED_RGBA_ASTC_5x4_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_5x5_KHR"] = 37810] = "COMPRESSED_RGBA_ASTC_5x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_6x5_KHR"] = 37811] = "COMPRESSED_RGBA_ASTC_6x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_6x6_KHR"] = 37812] = "COMPRESSED_RGBA_ASTC_6x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_8x5_KHR"] = 37813] = "COMPRESSED_RGBA_ASTC_8x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_8x6_KHR"] = 37814] = "COMPRESSED_RGBA_ASTC_8x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_8x8_KHR"] = 37815] = "COMPRESSED_RGBA_ASTC_8x8_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_10x5_KHR"] = 37816] = "COMPRESSED_RGBA_ASTC_10x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_10x6_KHR"] = 37817] = "COMPRESSED_RGBA_ASTC_10x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_10x8_KHR"] = 37818] = "COMPRESSED_RGBA_ASTC_10x8_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_10x10_KHR"] = 37819] = "COMPRESSED_RGBA_ASTC_10x10_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_12x10_KHR"] = 37820] = "COMPRESSED_RGBA_ASTC_12x10_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_ASTC_12x12_KHR"] = 37821] = "COMPRESSED_RGBA_ASTC_12x12_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"] = 37840] = "COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"] = 37841] = "COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"] = 37842] = "COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"] = 37843] = "COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"] = 37844] = "COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"] = 37845] = "COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"] = 37846] = "COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"] = 37847] = "COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"] = 37848] = "COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"] = 37849] = "COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"] = 37850] = "COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"] = 37851] = "COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"] = 37852] = "COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"] = 37853] = "COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGBA_BPTC_UNORM_EXT"] = 36492] = "COMPRESSED_RGBA_BPTC_UNORM_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT"] = 36493] = "COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT"] = 36494] = "COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT"; + GL_INTERNAL_FORMAT2[GL_INTERNAL_FORMAT2["COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT"] = 36495] = "COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT"; + return GL_INTERNAL_FORMAT2; + })(GL_INTERNAL_FORMAT || {}); + var GL_FORMATS$1 = /* @__PURE__ */ ((GL_FORMATS2) => { + GL_FORMATS2[GL_FORMATS2["RGBA"] = 6408] = "RGBA"; + GL_FORMATS2[GL_FORMATS2["RGB"] = 6407] = "RGB"; + GL_FORMATS2[GL_FORMATS2["RG"] = 33319] = "RG"; + GL_FORMATS2[GL_FORMATS2["RED"] = 6403] = "RED"; + GL_FORMATS2[GL_FORMATS2["RGBA_INTEGER"] = 36249] = "RGBA_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RGB_INTEGER"] = 36248] = "RGB_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RG_INTEGER"] = 33320] = "RG_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RED_INTEGER"] = 36244] = "RED_INTEGER"; + GL_FORMATS2[GL_FORMATS2["ALPHA"] = 6406] = "ALPHA"; + GL_FORMATS2[GL_FORMATS2["LUMINANCE"] = 6409] = "LUMINANCE"; + GL_FORMATS2[GL_FORMATS2["LUMINANCE_ALPHA"] = 6410] = "LUMINANCE_ALPHA"; + GL_FORMATS2[GL_FORMATS2["DEPTH_COMPONENT"] = 6402] = "DEPTH_COMPONENT"; + GL_FORMATS2[GL_FORMATS2["DEPTH_STENCIL"] = 34041] = "DEPTH_STENCIL"; + return GL_FORMATS2; + })(GL_FORMATS$1 || {}); + var GL_TYPES$1 = /* @__PURE__ */ ((GL_TYPES2) => { + GL_TYPES2[GL_TYPES2["UNSIGNED_BYTE"] = 5121] = "UNSIGNED_BYTE"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT"] = 5123] = "UNSIGNED_SHORT"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_5_6_5"] = 33635] = "UNSIGNED_SHORT_5_6_5"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_4_4_4_4"] = 32819] = "UNSIGNED_SHORT_4_4_4_4"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_5_5_5_1"] = 32820] = "UNSIGNED_SHORT_5_5_5_1"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT"] = 5125] = "UNSIGNED_INT"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_10F_11F_11F_REV"] = 35899] = "UNSIGNED_INT_10F_11F_11F_REV"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_2_10_10_10_REV"] = 33640] = "UNSIGNED_INT_2_10_10_10_REV"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_24_8"] = 34042] = "UNSIGNED_INT_24_8"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_5_9_9_9_REV"] = 35902] = "UNSIGNED_INT_5_9_9_9_REV"; + GL_TYPES2[GL_TYPES2["BYTE"] = 5120] = "BYTE"; + GL_TYPES2[GL_TYPES2["SHORT"] = 5122] = "SHORT"; + GL_TYPES2[GL_TYPES2["INT"] = 5124] = "INT"; + GL_TYPES2[GL_TYPES2["FLOAT"] = 5126] = "FLOAT"; + GL_TYPES2[GL_TYPES2["FLOAT_32_UNSIGNED_INT_24_8_REV"] = 36269] = "FLOAT_32_UNSIGNED_INT_24_8_REV"; + GL_TYPES2[GL_TYPES2["HALF_FLOAT"] = 36193] = "HALF_FLOAT"; + return GL_TYPES2; + })(GL_TYPES$1 || {}); + const INTERNAL_FORMAT_TO_TEXTURE_FORMATS = { + [33776 /* COMPRESSED_RGB_S3TC_DXT1_EXT */]: "bc1-rgba-unorm", + // TODO: ??? + [33777 /* COMPRESSED_RGBA_S3TC_DXT1_EXT */]: "bc1-rgba-unorm", + [33778 /* COMPRESSED_RGBA_S3TC_DXT3_EXT */]: "bc2-rgba-unorm", + [33779 /* COMPRESSED_RGBA_S3TC_DXT5_EXT */]: "bc3-rgba-unorm", + [35916 /* COMPRESSED_SRGB_S3TC_DXT1_EXT */]: "bc1-rgba-unorm-srgb", + // TODO: ??? + [35917 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT */]: "bc1-rgba-unorm-srgb", + [35918 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT */]: "bc2-rgba-unorm-srgb", + [35919 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT */]: "bc3-rgba-unorm-srgb", + [36283 /* COMPRESSED_RED_RGTC1_EXT */]: "bc4-r-unorm", + [36284 /* COMPRESSED_SIGNED_RED_RGTC1_EXT */]: "bc4-r-snorm", + [36285 /* COMPRESSED_RED_GREEN_RGTC2_EXT */]: "bc5-rg-unorm", + [36286 /* COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT */]: "bc5-rg-snorm", + [37488 /* COMPRESSED_R11_EAC */]: "eac-r11unorm", + // [GL_INTERNAL_FORMAT.COMPRESSED_SIGNED_R11_EAC]: 'eac-r11snorm', + [37490 /* COMPRESSED_RG11_EAC */]: "eac-rg11snorm", + // [GL_INTERNAL_FORMAT.COMPRESSED_SIGNED_RG11_EAC]: 'eac-rg11unorm', + [37492 /* COMPRESSED_RGB8_ETC2 */]: "etc2-rgb8unorm", + [37496 /* COMPRESSED_RGBA8_ETC2_EAC */]: "etc2-rgba8unorm", + [37493 /* COMPRESSED_SRGB8_ETC2 */]: "etc2-rgb8unorm-srgb", + [37497 /* COMPRESSED_SRGB8_ALPHA8_ETC2_EAC */]: "etc2-rgba8unorm-srgb", + [37494 /* COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 */]: "etc2-rgb8a1unorm", + [37495 /* COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 */]: "etc2-rgb8a1unorm-srgb", + [37808 /* COMPRESSED_RGBA_ASTC_4x4_KHR */]: "astc-4x4-unorm", + [37840 /* COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR */]: "astc-4x4-unorm-srgb", + [37809 /* COMPRESSED_RGBA_ASTC_5x4_KHR */]: "astc-5x4-unorm", + [37841 /* COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR */]: "astc-5x4-unorm-srgb", + [37810 /* COMPRESSED_RGBA_ASTC_5x5_KHR */]: "astc-5x5-unorm", + [37842 /* COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR */]: "astc-5x5-unorm-srgb", + [37811 /* COMPRESSED_RGBA_ASTC_6x5_KHR */]: "astc-6x5-unorm", + [37843 /* COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR */]: "astc-6x5-unorm-srgb", + [37812 /* COMPRESSED_RGBA_ASTC_6x6_KHR */]: "astc-6x6-unorm", + [37844 /* COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR */]: "astc-6x6-unorm-srgb", + [37813 /* COMPRESSED_RGBA_ASTC_8x5_KHR */]: "astc-8x5-unorm", + [37845 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR */]: "astc-8x5-unorm-srgb", + [37814 /* COMPRESSED_RGBA_ASTC_8x6_KHR */]: "astc-8x6-unorm", + [37846 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR */]: "astc-8x6-unorm-srgb", + [37815 /* COMPRESSED_RGBA_ASTC_8x8_KHR */]: "astc-8x8-unorm", + [37847 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR */]: "astc-8x8-unorm-srgb", + [37816 /* COMPRESSED_RGBA_ASTC_10x5_KHR */]: "astc-10x5-unorm", + [37848 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR */]: "astc-10x5-unorm-srgb", + [37817 /* COMPRESSED_RGBA_ASTC_10x6_KHR */]: "astc-10x6-unorm", + [37849 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR */]: "astc-10x6-unorm-srgb", + [37818 /* COMPRESSED_RGBA_ASTC_10x8_KHR */]: "astc-10x8-unorm", + [37850 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR */]: "astc-10x8-unorm-srgb", + [37819 /* COMPRESSED_RGBA_ASTC_10x10_KHR */]: "astc-10x10-unorm", + [37851 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR */]: "astc-10x10-unorm-srgb", + [37820 /* COMPRESSED_RGBA_ASTC_12x10_KHR */]: "astc-12x10-unorm", + [37852 /* COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR */]: "astc-12x10-unorm-srgb", + [37821 /* COMPRESSED_RGBA_ASTC_12x12_KHR */]: "astc-12x12-unorm", + [37853 /* COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR */]: "astc-12x12-unorm-srgb", + [36492 /* COMPRESSED_RGBA_BPTC_UNORM_EXT */]: "bc7-rgba-unorm", + [36493 /* COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT */]: "bc7-rgba-unorm-srgb", + [36494 /* COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT */]: "bc6h-rgb-float", + [36495 /* COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT */]: "bc6h-rgb-ufloat", + [35907 /* SRGB8_ALPHA8 */]: "rgba8unorm-srgb", + [36759 /* RGBA8_SNORM */]: "rgba8snorm", + [36220 /* RGBA8UI */]: "rgba8uint", + [36238 /* RGBA8I */]: "rgba8sint", + [6408 /* RGBA */]: "rgba8unorm" + // [GL_INTERNAL_FORMAT.RGBA8]: 'bgra8unorm' + }; + const FILE_IDENTIFIER = [171, 75, 84, 88, 32, 49, 49, 187, 13, 10, 26, 10]; + const FIELDS = { + FILE_IDENTIFIER: 0, + ENDIANNESS: 12, + GL_TYPE: 16, + GL_TYPE_SIZE: 20, + GL_FORMAT: 24, + GL_INTERNAL_FORMAT: 28, + GL_BASE_INTERNAL_FORMAT: 32, + PIXEL_WIDTH: 36, + PIXEL_HEIGHT: 40, + PIXEL_DEPTH: 44, + NUMBER_OF_ARRAY_ELEMENTS: 48, + NUMBER_OF_FACES: 52, + NUMBER_OF_MIPMAP_LEVELS: 56, + BYTES_OF_KEY_VALUE_DATA: 60 + }; + const FILE_HEADER_SIZE = 64; + const ENDIANNESS = 67305985; + const TYPES_TO_BYTES_PER_COMPONENT = { + [5121 /* UNSIGNED_BYTE */]: 1, + [5123 /* UNSIGNED_SHORT */]: 2, + [5124 /* INT */]: 4, + [5125 /* UNSIGNED_INT */]: 4, + [5126 /* FLOAT */]: 4, + [36193 /* HALF_FLOAT */]: 8 + }; + const FORMATS_TO_COMPONENTS = { + [6408 /* RGBA */]: 4, + [6407 /* RGB */]: 3, + [33319 /* RG */]: 2, + [6403 /* RED */]: 1, + [6409 /* LUMINANCE */]: 1, + [6410 /* LUMINANCE_ALPHA */]: 2, + [6406 /* ALPHA */]: 1 + }; + const TYPES_TO_BYTES_PER_PIXEL = { + [32819 /* UNSIGNED_SHORT_4_4_4_4 */]: 2, + [32820 /* UNSIGNED_SHORT_5_5_5_1 */]: 2, + [33635 /* UNSIGNED_SHORT_5_6_5 */]: 2 + }; + const INTERNAL_FORMAT_TO_BYTES_PER_PIXEL = { + [33776 /* COMPRESSED_RGB_S3TC_DXT1_EXT */]: 0.5, + [33777 /* COMPRESSED_RGBA_S3TC_DXT1_EXT */]: 0.5, + [33778 /* COMPRESSED_RGBA_S3TC_DXT3_EXT */]: 1, + [33779 /* COMPRESSED_RGBA_S3TC_DXT5_EXT */]: 1, + [35916 /* COMPRESSED_SRGB_S3TC_DXT1_EXT */]: 0.5, + [35917 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT */]: 0.5, + [35918 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT */]: 1, + [35919 /* COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT */]: 1, + [36283 /* COMPRESSED_RED_RGTC1_EXT */]: 0.5, + [36284 /* COMPRESSED_SIGNED_RED_RGTC1_EXT */]: 0.5, + [36285 /* COMPRESSED_RED_GREEN_RGTC2_EXT */]: 1, + [36286 /* COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT */]: 1, + [37488 /* COMPRESSED_R11_EAC */]: 0.5, + [37489 /* COMPRESSED_SIGNED_R11_EAC */]: 0.5, + [37490 /* COMPRESSED_RG11_EAC */]: 1, + [37491 /* COMPRESSED_SIGNED_RG11_EAC */]: 1, + [37492 /* COMPRESSED_RGB8_ETC2 */]: 0.5, + [37496 /* COMPRESSED_RGBA8_ETC2_EAC */]: 1, + [37493 /* COMPRESSED_SRGB8_ETC2 */]: 0.5, + [37497 /* COMPRESSED_SRGB8_ALPHA8_ETC2_EAC */]: 1, + [37494 /* COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 */]: 0.5, + [37495 /* COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 */]: 0.5, + [37808 /* COMPRESSED_RGBA_ASTC_4x4_KHR */]: 1, + [37840 /* COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR */]: 1, + [37809 /* COMPRESSED_RGBA_ASTC_5x4_KHR */]: 0.8, + [37841 /* COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR */]: 0.8, + [37810 /* COMPRESSED_RGBA_ASTC_5x5_KHR */]: 0.64, + [37842 /* COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR */]: 0.64, + [37811 /* COMPRESSED_RGBA_ASTC_6x5_KHR */]: 0.53375, + [37843 /* COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR */]: 0.53375, + [37812 /* COMPRESSED_RGBA_ASTC_6x6_KHR */]: 0.445, + [37844 /* COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR */]: 0.445, + [37813 /* COMPRESSED_RGBA_ASTC_8x5_KHR */]: 0.4, + [37845 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR */]: 0.4, + [37814 /* COMPRESSED_RGBA_ASTC_8x6_KHR */]: 0.33375, + [37846 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR */]: 0.33375, + [37815 /* COMPRESSED_RGBA_ASTC_8x8_KHR */]: 0.25, + [37847 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR */]: 0.25, + [37816 /* COMPRESSED_RGBA_ASTC_10x5_KHR */]: 0.32, + [37848 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR */]: 0.32, + [37817 /* COMPRESSED_RGBA_ASTC_10x6_KHR */]: 0.26625, + [37849 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR */]: 0.26625, + [37818 /* COMPRESSED_RGBA_ASTC_10x8_KHR */]: 0.2, + [37850 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR */]: 0.2, + [37819 /* COMPRESSED_RGBA_ASTC_10x10_KHR */]: 0.16, + [37851 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR */]: 0.16, + [37820 /* COMPRESSED_RGBA_ASTC_12x10_KHR */]: 0.13375, + [37852 /* COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR */]: 0.13375, + [37821 /* COMPRESSED_RGBA_ASTC_12x12_KHR */]: 0.11125, + [37853 /* COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR */]: 0.11125, + [36492 /* COMPRESSED_RGBA_BPTC_UNORM_EXT */]: 1, + [36493 /* COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT */]: 1, + [36494 /* COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT */]: 1, + [36495 /* COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT */]: 1 + }; + const KTX = { + FILE_HEADER_SIZE, + FILE_IDENTIFIER, + FORMATS_TO_COMPONENTS, + INTERNAL_FORMAT_TO_BYTES_PER_PIXEL, + INTERNAL_FORMAT_TO_TEXTURE_FORMATS, + FIELDS, + TYPES_TO_BYTES_PER_COMPONENT, + TYPES_TO_BYTES_PER_PIXEL, + ENDIANNESS + }; + + "use strict"; + function parseKTX(arrayBuffer, supportedFormats) { + const dataView = new DataView(arrayBuffer); + if (!validate(dataView)) { + throw new Error("Invalid KTX identifier in header"); + } + const { + littleEndian, + glType, + glFormat, + glInternalFormat, + pixelWidth, + pixelHeight, + numberOfMipmapLevels, + offset + } = parseKTXHeader(dataView); + const textureFormat = KTX.INTERNAL_FORMAT_TO_TEXTURE_FORMATS[glInternalFormat]; + if (!textureFormat) { + throw new Error(`Unknown texture format ${glInternalFormat}`); + } + if (!supportedFormats.includes(textureFormat)) { + throw new Error(`Unsupported texture format: ${textureFormat}, supportedFormats: ${supportedFormats}`); + } + const imagePixelByteSize = getImagePixelByteSize(glType, glFormat, glInternalFormat); + const imageBuffers = getImageBuffers( + dataView, + glType, + imagePixelByteSize, + pixelWidth, + pixelHeight, + offset, + numberOfMipmapLevels, + littleEndian + ); + return { + format: textureFormat, + width: pixelWidth, + height: pixelHeight, + resource: imageBuffers, + alphaMode: "no-premultiply-alpha" + }; + } + function getImageBuffers(dataView, glType, imagePixelByteSize, pixelWidth, pixelHeight, offset, numberOfMipmapLevels, littleEndian) { + const alignedWidth = pixelWidth + 3 & ~3; + const alignedHeight = pixelHeight + 3 & ~3; + let imagePixels = pixelWidth * pixelHeight; + if (glType === 0) { + imagePixels = alignedWidth * alignedHeight; + } + let mipByteSize = imagePixels * imagePixelByteSize; + let mipWidth = pixelWidth; + let mipHeight = pixelHeight; + let alignedMipWidth = alignedWidth; + let alignedMipHeight = alignedHeight; + let imageOffset = offset; + const imageBuffers = new Array(numberOfMipmapLevels); + for (let mipmapLevel = 0; mipmapLevel < numberOfMipmapLevels; mipmapLevel++) { + const imageSize = dataView.getUint32(imageOffset, littleEndian); + let elementOffset = imageOffset + 4; + imageBuffers[mipmapLevel] = new Uint8Array(dataView.buffer, elementOffset, mipByteSize); + elementOffset += mipByteSize; + imageOffset += imageSize + 4; + imageOffset = imageOffset % 4 !== 0 ? imageOffset + 4 - imageOffset % 4 : imageOffset; + mipWidth = mipWidth >> 1 || 1; + mipHeight = mipHeight >> 1 || 1; + alignedMipWidth = mipWidth + 4 - 1 & ~(4 - 1); + alignedMipHeight = mipHeight + 4 - 1 & ~(4 - 1); + mipByteSize = alignedMipWidth * alignedMipHeight * imagePixelByteSize; + } + return imageBuffers; + } + function getImagePixelByteSize(glType, glFormat, glInternalFormat) { + let imagePixelByteSize = KTX.INTERNAL_FORMAT_TO_BYTES_PER_PIXEL[glInternalFormat]; + if (glType !== 0) { + if (KTX.TYPES_TO_BYTES_PER_COMPONENT[glType]) { + imagePixelByteSize = KTX.TYPES_TO_BYTES_PER_COMPONENT[glType] * KTX.FORMATS_TO_COMPONENTS[glFormat]; + } else { + imagePixelByteSize = KTX.TYPES_TO_BYTES_PER_PIXEL[glType]; + } + } + if (imagePixelByteSize === void 0) { + throw new Error("Unable to resolve the pixel format stored in the *.ktx file!"); + } + return imagePixelByteSize; + } + function parseKTXHeader(dataView) { + const littleEndian = dataView.getUint32(KTX.FIELDS.ENDIANNESS, true) === KTX.ENDIANNESS; + const glType = dataView.getUint32(KTX.FIELDS.GL_TYPE, littleEndian); + const glFormat = dataView.getUint32(KTX.FIELDS.GL_FORMAT, littleEndian); + const glInternalFormat = dataView.getUint32(KTX.FIELDS.GL_INTERNAL_FORMAT, littleEndian); + const pixelWidth = dataView.getUint32(KTX.FIELDS.PIXEL_WIDTH, littleEndian); + const pixelHeight = dataView.getUint32(KTX.FIELDS.PIXEL_HEIGHT, littleEndian) || 1; + const pixelDepth = dataView.getUint32(KTX.FIELDS.PIXEL_DEPTH, littleEndian) || 1; + const numberOfArrayElements = dataView.getUint32(KTX.FIELDS.NUMBER_OF_ARRAY_ELEMENTS, littleEndian) || 1; + const numberOfFaces = dataView.getUint32(KTX.FIELDS.NUMBER_OF_FACES, littleEndian); + const numberOfMipmapLevels = dataView.getUint32(KTX.FIELDS.NUMBER_OF_MIPMAP_LEVELS, littleEndian); + const bytesOfKeyValueData = dataView.getUint32(KTX.FIELDS.BYTES_OF_KEY_VALUE_DATA, littleEndian); + if (pixelHeight === 0 || pixelDepth !== 1) { + throw new Error("Only 2D textures are supported"); + } + if (numberOfFaces !== 1) { + throw new Error("CubeTextures are not supported by KTXLoader yet!"); + } + if (numberOfArrayElements !== 1) { + throw new Error("WebGL does not support array textures"); + } + return { + littleEndian, + glType, + glFormat, + glInternalFormat, + pixelWidth, + pixelHeight, + numberOfMipmapLevels, + offset: KTX.FILE_HEADER_SIZE + bytesOfKeyValueData + }; + } + function validate(dataView) { + for (let i = 0; i < KTX.FILE_IDENTIFIER.length; i++) { + if (dataView.getUint8(i) !== KTX.FILE_IDENTIFIER[i]) { + return false; + } + } + return true; + } + + "use strict"; + const loadKTX = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.High, + name: "loadKTX" + }, + name: "loadKTX", + test(url) { + return checkExtension(url, ".ktx"); + }, + async load(url, _asset, loader) { + const supportedTextures = await getSupportedTextureFormats(); + const ktxResponse = await fetch(url); + const ktxArrayBuffer = await ktxResponse.arrayBuffer(); + const textureOptions = parseKTX(ktxArrayBuffer, supportedTextures); + const compressedTextureSource = new CompressedSource(textureOptions); + return createTexture(compressedTextureSource, loader, url); + }, + unload(texture) { + if (Array.isArray(texture)) { + texture.forEach((t) => t.destroy(true)); + } else { + texture.destroy(true); + } + } + }; + + const WORKER_CODE = "(function () {\n 'use strict';\n\n const converters = {\n rgb8unorm: {\n convertedFormat: \"rgba8unorm\",\n convertFunction: convertRGBtoRGBA\n },\n \"rgb8unorm-srgb\": {\n convertedFormat: \"rgba8unorm-srgb\",\n convertFunction: convertRGBtoRGBA\n }\n };\n function convertFormatIfRequired(textureOptions) {\n const format = textureOptions.format;\n if (converters[format]) {\n const convertFunction = converters[format].convertFunction;\n const levelBuffers = textureOptions.resource;\n for (let i = 0; i < levelBuffers.length; i++) {\n levelBuffers[i] = convertFunction(levelBuffers[i]);\n }\n textureOptions.format = converters[format].convertedFormat;\n }\n }\n function convertRGBtoRGBA(levelBuffer) {\n const pixelCount = levelBuffer.byteLength / 3;\n const levelBufferWithAlpha = new Uint32Array(pixelCount);\n for (let i = 0; i < pixelCount; ++i) {\n levelBufferWithAlpha[i] = levelBuffer[i * 3] + (levelBuffer[i * 3 + 1] << 8) + (levelBuffer[i * 3 + 2] << 16) + 4278190080;\n }\n return new Uint8Array(levelBufferWithAlpha.buffer);\n }\n\n function createLevelBuffersFromKTX(ktxTexture) {\n const levelBuffers = [];\n for (let i = 0; i < ktxTexture.numLevels; i++) {\n const imageData = ktxTexture.getImageData(i, 0, 0);\n const levelBuffer = new Uint8Array(imageData.byteLength);\n levelBuffer.set(imageData);\n levelBuffers.push(levelBuffer);\n }\n return levelBuffers;\n }\n\n const glFormatToGPUFormatMap = {\n 6408: \"rgba8unorm\",\n 32856: \"bgra8unorm\",\n //\n 32857: \"rgb10a2unorm\",\n 33189: \"depth16unorm\",\n 33190: \"depth24plus\",\n 33321: \"r8unorm\",\n 33323: \"rg8unorm\",\n 33325: \"r16float\",\n 33326: \"r32float\",\n 33327: \"rg16float\",\n 33328: \"rg32float\",\n 33329: \"r8sint\",\n 33330: \"r8uint\",\n 33331: \"r16sint\",\n 33332: \"r16uint\",\n 33333: \"r32sint\",\n 33334: \"r32uint\",\n 33335: \"rg8sint\",\n 33336: \"rg8uint\",\n 33337: \"rg16sint\",\n 33338: \"rg16uint\",\n 33339: \"rg32sint\",\n 33340: \"rg32uint\",\n 33778: \"bc2-rgba-unorm\",\n 33779: \"bc3-rgba-unorm\",\n 34836: \"rgba32float\",\n 34842: \"rgba16float\",\n 35056: \"depth24plus-stencil8\",\n 35898: \"rg11b10ufloat\",\n 35901: \"rgb9e5ufloat\",\n 35907: \"rgba8unorm-srgb\",\n // bgra8unorm-srgb\n 36012: \"depth32float\",\n 36013: \"depth32float-stencil8\",\n 36168: \"stencil8\",\n 36208: \"rgba32uint\",\n 36214: \"rgba16uint\",\n 36220: \"rgba8uint\",\n 36226: \"rgba32sint\",\n 36232: \"rgba16sint\",\n 36238: \"rgba8sint\",\n 36492: \"bc7-rgba-unorm\",\n 36756: \"r8snorm\",\n 36757: \"rg8snorm\",\n 36759: \"rgba8snorm\",\n 37496: \"etc2-rgba8unorm\",\n 37808: \"astc-4x4-unorm\"\n };\n function glFormatToGPUFormat(glInternalFormat) {\n const format = glFormatToGPUFormatMap[glInternalFormat];\n if (format) {\n return format;\n }\n throw new Error(`Unsupported glInternalFormat: ${glInternalFormat}`);\n }\n\n const vkFormatToGPUFormatMap = {\n 23: \"rgb8unorm\",\n // VK_FORMAT_R8G8B8_UNORM\n 37: \"rgba8unorm\",\n // VK_FORMAT_R8G8B8A8_UNORM\n 43: \"rgba8unorm-srgb\"\n // VK_FORMAT_R8G8B8A8_SRGB\n // TODO add more!\n };\n function vkFormatToGPUFormat(vkFormat) {\n const format = vkFormatToGPUFormatMap[vkFormat];\n if (format) {\n return format;\n }\n throw new Error(`Unsupported VkFormat: ${vkFormat}`);\n }\n\n function getTextureFormatFromKTXTexture(ktxTexture) {\n if (ktxTexture.classId === 2) {\n return vkFormatToGPUFormat(ktxTexture.vkFormat);\n }\n return glFormatToGPUFormat(ktxTexture.glInternalformat);\n }\n\n const gpuFormatToBasisTranscoderFormatMap = {\n \"bc3-rgba-unorm\": \"BC3_RGBA\",\n \"bc7-rgba-unorm\": \"BC7_M5_RGBA\",\n \"etc2-rgba8unorm\": \"ETC2_RGBA\",\n \"astc-4x4-unorm\": \"ASTC_4x4_RGBA\",\n // Uncompressed\n rgba8unorm: \"RGBA32\",\n rg11b10ufloat: \"R11F_G11F_B10F\"\n };\n function gpuFormatToKTXBasisTranscoderFormat(transcoderFormat) {\n const format = gpuFormatToBasisTranscoderFormatMap[transcoderFormat];\n if (format) {\n return format;\n }\n throw new Error(`Unsupported transcoderFormat: ${transcoderFormat}`);\n }\n\n const settings = {\n jsUrl: \"\",\n wasmUrl: \"\"\n };\n let basisTranscoderFormat;\n let basisTranscodedTextureFormat;\n let ktxPromise;\n async function getKTX() {\n if (!ktxPromise) {\n const absoluteJsUrl = new URL(settings.jsUrl, location.origin).href;\n const absoluteWasmUrl = new URL(settings.wasmUrl, location.origin).href;\n importScripts(absoluteJsUrl);\n ktxPromise = new Promise((resolve) => {\n LIBKTX({\n locateFile: (_file) => absoluteWasmUrl\n }).then((libktx) => {\n resolve(libktx);\n });\n });\n }\n return ktxPromise;\n }\n async function fetchKTXTexture(url, ktx) {\n const ktx2Response = await fetch(url);\n if (ktx2Response.ok) {\n const ktx2ArrayBuffer = await ktx2Response.arrayBuffer();\n return new ktx.ktxTexture(new Uint8Array(ktx2ArrayBuffer));\n }\n throw new Error(`Failed to load KTX(2) texture: ${url}`);\n }\n const preferredTranscodedFormat = [\n \"bc7-rgba-unorm\",\n \"astc-4x4-unorm\",\n \"etc2-rgba8unorm\",\n \"bc3-rgba-unorm\",\n \"rgba8unorm\"\n ];\n async function load(url) {\n const ktx = await getKTX();\n const ktxTexture = await fetchKTXTexture(url, ktx);\n let format;\n if (ktxTexture.needsTranscoding) {\n format = basisTranscodedTextureFormat;\n const transcodeFormat = ktx.TranscodeTarget[basisTranscoderFormat];\n const result = ktxTexture.transcodeBasis(transcodeFormat, 0);\n if (result !== ktx.ErrorCode.SUCCESS) {\n throw new Error(\"Unable to transcode basis texture.\");\n }\n } else {\n format = getTextureFormatFromKTXTexture(ktxTexture);\n }\n const levelBuffers = createLevelBuffersFromKTX(ktxTexture);\n const textureOptions = {\n width: ktxTexture.baseWidth,\n height: ktxTexture.baseHeight,\n format,\n mipLevelCount: ktxTexture.numLevels,\n resource: levelBuffers,\n alphaMode: \"no-premultiply-alpha\"\n };\n convertFormatIfRequired(textureOptions);\n return textureOptions;\n }\n async function init(jsUrl, wasmUrl, supportedTextures) {\n if (jsUrl)\n settings.jsUrl = jsUrl;\n if (wasmUrl)\n settings.wasmUrl = wasmUrl;\n basisTranscodedTextureFormat = preferredTranscodedFormat.filter((format) => supportedTextures.includes(format))[0];\n basisTranscoderFormat = gpuFormatToKTXBasisTranscoderFormat(basisTranscodedTextureFormat);\n await getKTX();\n }\n const messageHandlers = {\n init: async (data) => {\n const { jsUrl, wasmUrl, supportedTextures } = data;\n await init(jsUrl, wasmUrl, supportedTextures);\n },\n load: async (data) => {\n var _a;\n try {\n const textureOptions = await load(data.url);\n return {\n type: \"load\",\n url: data.url,\n success: true,\n textureOptions,\n transferables: (_a = textureOptions.resource) == null ? void 0 : _a.map((arr) => arr.buffer)\n };\n } catch (e) {\n throw e;\n }\n }\n };\n self.onmessage = async (messageEvent) => {\n var _a;\n const message = messageEvent.data;\n const response = await ((_a = messageHandlers[message.type]) == null ? void 0 : _a.call(messageHandlers, message));\n if (response) {\n self.postMessage(response, response.transferables);\n }\n };\n\n})();\n"; + let WORKER_URL = null; + class WorkerInstance + { + constructor() + { + if (!WORKER_URL) + { + WORKER_URL = URL.createObjectURL(new Blob([WORKER_CODE], { type: 'application/javascript' })); + } + this.worker = new Worker(WORKER_URL); + } + } + WorkerInstance.revokeObjectURL = function revokeObjectURL() + { + if (WORKER_URL) + { + URL.revokeObjectURL(WORKER_URL); + WORKER_URL = null; + } + }; + + "use strict"; + const ktxTranscoderUrls = { + jsUrl: "https://files.pixijs.download/transcoders/ktx/libktx.js", + wasmUrl: "https://files.pixijs.download/transcoders/ktx/libktx.wasm" + }; + function setKTXTranscoderPath(config) { + Object.assign(ktxTranscoderUrls, config); + } + + "use strict"; + let ktxWorker; + const urlHash = {}; + function getKTX2Worker(supportedTextures) { + if (!ktxWorker) { + ktxWorker = new WorkerInstance().worker; + ktxWorker.onmessage = (messageEvent) => { + const { success, url, textureOptions } = messageEvent.data; + if (!success) { + console.warn("Failed to load KTX texture", url); + } + urlHash[url](textureOptions); + }; + ktxWorker.postMessage({ + type: "init", + jsUrl: ktxTranscoderUrls.jsUrl, + wasmUrl: ktxTranscoderUrls.wasmUrl, + supportedTextures + }); + } + return ktxWorker; + } + function loadKTX2onWorker(url, supportedTextures) { + const ktxWorker2 = getKTX2Worker(supportedTextures); + return new Promise((resolve) => { + urlHash[url] = resolve; + ktxWorker2.postMessage({ type: "load", url }); + }); + } + + "use strict"; + const loadKTX2 = { + extension: { + type: ExtensionType.LoadParser, + priority: LoaderParserPriority.High, + name: "loadKTX2" + }, + name: "loadKTX2", + test(url) { + return checkExtension(url, ".ktx2"); + }, + async load(url, _asset, loader) { + const supportedTextures = await getSupportedTextureFormats(); + const textureOptions = await loadKTX2onWorker(url, supportedTextures); + const compressedTextureSource = new CompressedSource(textureOptions); + return createTexture(compressedTextureSource, loader, url); + }, + async unload(texture) { + if (Array.isArray(texture)) { + texture.forEach((t) => t.destroy(true)); + } else { + texture.destroy(true); + } + } + }; + + "use strict"; + + "use strict"; + const converters = { + rgb8unorm: { + convertedFormat: "rgba8unorm", + convertFunction: convertRGBtoRGBA + }, + "rgb8unorm-srgb": { + convertedFormat: "rgba8unorm-srgb", + convertFunction: convertRGBtoRGBA + } + }; + function convertFormatIfRequired(textureOptions) { + const format = textureOptions.format; + if (converters[format]) { + const convertFunction = converters[format].convertFunction; + const levelBuffers = textureOptions.resource; + for (let i = 0; i < levelBuffers.length; i++) { + levelBuffers[i] = convertFunction(levelBuffers[i]); + } + textureOptions.format = converters[format].convertedFormat; + } + } + function convertRGBtoRGBA(levelBuffer) { + const pixelCount = levelBuffer.byteLength / 3; + const levelBufferWithAlpha = new Uint32Array(pixelCount); + for (let i = 0; i < pixelCount; ++i) { + levelBufferWithAlpha[i] = levelBuffer[i * 3] + (levelBuffer[i * 3 + 1] << 8) + (levelBuffer[i * 3 + 2] << 16) + 4278190080; + } + return new Uint8Array(levelBufferWithAlpha.buffer); + } + + "use strict"; + function createLevelBuffersFromKTX(ktxTexture) { + const levelBuffers = []; + for (let i = 0; i < ktxTexture.numLevels; i++) { + const imageData = ktxTexture.getImageData(i, 0, 0); + const levelBuffer = new Uint8Array(imageData.byteLength); + levelBuffer.set(imageData); + levelBuffers.push(levelBuffer); + } + return levelBuffers; + } + + "use strict"; + const glFormatToGPUFormatMap = { + 6408: "rgba8unorm", + 32856: "bgra8unorm", + // + 32857: "rgb10a2unorm", + 33189: "depth16unorm", + 33190: "depth24plus", + 33321: "r8unorm", + 33323: "rg8unorm", + 33325: "r16float", + 33326: "r32float", + 33327: "rg16float", + 33328: "rg32float", + 33329: "r8sint", + 33330: "r8uint", + 33331: "r16sint", + 33332: "r16uint", + 33333: "r32sint", + 33334: "r32uint", + 33335: "rg8sint", + 33336: "rg8uint", + 33337: "rg16sint", + 33338: "rg16uint", + 33339: "rg32sint", + 33340: "rg32uint", + 33778: "bc2-rgba-unorm", + 33779: "bc3-rgba-unorm", + 34836: "rgba32float", + 34842: "rgba16float", + 35056: "depth24plus-stencil8", + 35898: "rg11b10ufloat", + 35901: "rgb9e5ufloat", + 35907: "rgba8unorm-srgb", + // bgra8unorm-srgb + 36012: "depth32float", + 36013: "depth32float-stencil8", + 36168: "stencil8", + 36208: "rgba32uint", + 36214: "rgba16uint", + 36220: "rgba8uint", + 36226: "rgba32sint", + 36232: "rgba16sint", + 36238: "rgba8sint", + 36492: "bc7-rgba-unorm", + 36756: "r8snorm", + 36757: "rg8snorm", + 36759: "rgba8snorm", + 37496: "etc2-rgba8unorm", + 37808: "astc-4x4-unorm" + }; + function glFormatToGPUFormat(glInternalFormat) { + const format = glFormatToGPUFormatMap[glInternalFormat]; + if (format) { + return format; + } + throw new Error(`Unsupported glInternalFormat: ${glInternalFormat}`); + } + + "use strict"; + const vkFormatToGPUFormatMap = { + 23: "rgb8unorm", + // VK_FORMAT_R8G8B8_UNORM + 37: "rgba8unorm", + // VK_FORMAT_R8G8B8A8_UNORM + 43: "rgba8unorm-srgb" + // VK_FORMAT_R8G8B8A8_SRGB + // TODO add more! + }; + function vkFormatToGPUFormat(vkFormat) { + const format = vkFormatToGPUFormatMap[vkFormat]; + if (format) { + return format; + } + throw new Error(`Unsupported VkFormat: ${vkFormat}`); + } + + "use strict"; + function getTextureFormatFromKTXTexture(ktxTexture) { + if (ktxTexture.classId === 2) { + return vkFormatToGPUFormat(ktxTexture.vkFormat); + } + return glFormatToGPUFormat(ktxTexture.glInternalformat); + } + + "use strict"; + const gpuFormatToBasisTranscoderFormatMap = { + "bc3-rgba-unorm": "BC3_RGBA", + "bc7-rgba-unorm": "BC7_M5_RGBA", + "etc2-rgba8unorm": "ETC2_RGBA", + "astc-4x4-unorm": "ASTC_4x4_RGBA", + // Uncompressed + rgba8unorm: "RGBA32", + rg11b10ufloat: "R11F_G11F_B10F" + }; + function gpuFormatToKTXBasisTranscoderFormat(transcoderFormat) { + const format = gpuFormatToBasisTranscoderFormatMap[transcoderFormat]; + if (format) { + return format; + } + throw new Error(`Unsupported transcoderFormat: ${transcoderFormat}`); + } + + "use strict"; + const validFormats = ["basis", "bc7", "bc6h", "astc", "etc2", "bc5", "bc4", "bc3", "bc2", "bc1", "eac"]; + const resolveCompressedTextureUrl = { + extension: ExtensionType.ResolveParser, + test: (value) => checkExtension(value, [".ktx", ".ktx2", ".dds"]), + parse: (value) => { + var _a, _b; + let format; + const splitValue = value.split("."); + if (splitValue.length > 2) { + const newFormat = splitValue[splitValue.length - 2]; + if (validFormats.includes(newFormat)) { + format = newFormat; + } + } else { + format = splitValue[splitValue.length - 1]; + } + return { + resolution: parseFloat((_b = (_a = Resolver.RETINA_PREFIX.exec(value)) == null ? void 0 : _a[1]) != null ? _b : "1"), + format, + src: value + }; + } + }; + + "use strict"; + let compressedTextureExtensions; + const detectCompressed = { + extension: { + type: ExtensionType.DetectionParser, + priority: 2 + }, + test: async () => { + if (await isWebGPUSupported()) + return true; + if (isWebGLSupported()) + return true; + return false; + }, + add: async (formats) => { + const supportedCompressedTextureFormats = await getSupportedCompressedTextureFormats(); + compressedTextureExtensions = extractExtensionsForCompressedTextureFormats(supportedCompressedTextureFormats); + return [...compressedTextureExtensions, ...formats]; + }, + remove: async (formats) => { + if (compressedTextureExtensions) { + return formats.filter((f) => !(f in compressedTextureExtensions)); + } + return formats; + } + }; + function extractExtensionsForCompressedTextureFormats(formats) { + const extensions = ["basis"]; + const dupeMap = {}; + formats.forEach((format) => { + const extension = format.split("-")[0]; + if (extension && !dupeMap[extension]) { + dupeMap[extension] = true; + extensions.push(extension); + } + }); + extensions.sort((a, b) => { + const aIndex = validFormats.indexOf(a); + const bIndex = validFormats.indexOf(b); + if (aIndex === -1) { + return 1; + } + if (bIndex === -1) { + return -1; + } + return aIndex - bIndex; + }); + return extensions; + } + + "use strict"; + + "use strict"; + const tempBounds$2 = new Bounds(); + const _Culler = class _Culler { + /** + * Culls the children of a specific container based on the given view. This will also cull items that are not + * being explicitly managed by the culler. + * @param container - The container to cull. + * @param view - The view rectangle. + * @param skipUpdateTransform - Whether to skip updating the transform. + */ + cull(container, view, skipUpdateTransform = true) { + this._cullRecursive(container, view, skipUpdateTransform); + } + _cullRecursive(container, view, skipUpdateTransform = true) { + var _a; + if (container.cullable && container.measurable && container.includeInBuild) { + const bounds = (_a = container.cullArea) != null ? _a : getGlobalBounds(container, skipUpdateTransform, tempBounds$2); + container.culled = !(bounds.x >= view.x + view.width || bounds.y >= view.y + view.height || bounds.x + bounds.width <= view.x || bounds.y + bounds.height <= view.y); + } + if (!container.cullableChildren || container.culled || !container.renderable || !container.measurable || !container.includeInBuild) + return; + for (let i = 0; i < container.children.length; i++) { + this._cullRecursive(container.children[i], view, skipUpdateTransform); + } + } + }; + /** A shared instance of the Culler class. */ + _Culler.shared = new _Culler(); + let Culler = _Culler; + + "use strict"; + class CullerPlugin { + static init() { + this._renderRef = this.render.bind(this); + this.render = () => { + Culler.shared.cull(this.stage, this.renderer.screen); + this.renderer.render({ container: this.stage }); + }; + } + static destroy() { + this.render = this._renderRef; + } + } + /** @ignore */ + CullerPlugin.extension = { + priority: 10, + type: ExtensionType.Application, + name: "culler" + }; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + const browserExt = { + extension: { + type: ExtensionType.Environment, + name: "browser", + priority: -1 + }, + test: () => true, + load: async () => { + await Promise.resolve().then(function () { return browserAll; }); + } + }; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + var __defProp$v = Object.defineProperty; + var __getOwnPropSymbols$v = Object.getOwnPropertySymbols; + var __hasOwnProp$v = Object.prototype.hasOwnProperty; + var __propIsEnum$v = Object.prototype.propertyIsEnumerable; + var __defNormalProp$v = (obj, key, value) => key in obj ? __defProp$v(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$v = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$v.call(b, prop)) + __defNormalProp$v(a, prop, b[prop]); + if (__getOwnPropSymbols$v) + for (var prop of __getOwnPropSymbols$v(b)) { + if (__propIsEnum$v.call(b, prop)) + __defNormalProp$v(a, prop, b[prop]); + } + return a; + }; + var __objRest$d = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$v.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$v) + for (var prop of __getOwnPropSymbols$v(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$v.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + const _Filter = class _Filter extends Shader { + /** + * @param options - The optional parameters of this filter. + */ + constructor(options) { + options = __spreadValues$v(__spreadValues$v({}, _Filter.defaultOptions), options); + super(options); + /** If enabled is true the filter is applied, if false it will not. */ + this.enabled = true; + /** + * The gpu state the filter requires to render. + * @internal + * @ignore + */ + this._state = State.for2d(); + this.padding = options.padding; + if (typeof options.antialias === "boolean") { + this.antialias = options.antialias ? "on" : "off"; + } else { + this.antialias = options.antialias; + } + this.resolution = options.resolution; + this.blendRequired = options.blendRequired; + this.addResource("uTexture", 0, 1); + } + /** + * Applies the filter + * @param filterManager - The renderer to retrieve the filter from + * @param input - The input render target. + * @param output - The target to output to. + * @param clearMode - Should the output be cleared before rendering to it + */ + apply(filterManager, input, output, clearMode) { + filterManager.applyFilter(this, input, output, clearMode); + } + /** + * Get the blend mode of the filter. + * @default "normal" + */ + get blendMode() { + return this._state.blendMode; + } + /** Sets the blend mode of the filter. */ + set blendMode(value) { + this._state.blendMode = value; + } + /** + * A short hand function to create a filter based of a vertex and fragment shader src. + * @param options + * @returns A shiny new PixiJS filter! + */ + static from(options) { + const _a = options, { gpu, gl } = _a, rest = __objRest$d(_a, ["gpu", "gl"]); + let gpuProgram; + let glProgram; + if (gpu) { + gpuProgram = GpuProgram.from(gpu); + } + if (gl) { + glProgram = GlProgram.from(gl); + } + return new _Filter(__spreadValues$v({ + gpuProgram, + glProgram + }, rest)); + } + }; + /** + * The default filter settings + * @static + */ + _Filter.defaultOptions = { + blendMode: "normal", + resolution: 1, + padding: 0, + antialias: "off", + blendRequired: false + }; + let Filter = _Filter; + + var blendTemplateFrag = "\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nout vec4 finalColor;\n\nuniform float uBlend;\n\nuniform sampler2D uTexture;\nuniform sampler2D uBackTexture;\n\n{FUNCTIONS}\n\nvoid main()\n{ \n vec4 back = texture(uBackTexture, vTextureCoord);\n vec4 front = texture(uTexture, vTextureCoord);\n\n {MAIN}\n}\n"; + + var blendTemplateVert = "in vec2 aPosition;\nout vec2 vTextureCoord;\nout vec2 backgroundUv;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n \n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n"; + + var blendTemplate = "\nstruct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct BlendUniforms {\n uBlend:f32,\n};\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n@group(0) @binding(3) var uBackTexture: texture_2d;\n\n@group(1) @binding(0) var blendUniforms : BlendUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition)\n );\n}\n\n{FUNCTIONS}\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2\n) -> @location(0) vec4 {\n\n\n var back = textureSample(uBackTexture, uSampler, uv);\n var front = textureSample(uTexture, uSampler, uv);\n \n var out = vec4(0.0,0.0,0.0,0.0);\n\n {MAIN}\n\n return out;\n}"; + + "use strict"; + var __defProp$u = Object.defineProperty; + var __getOwnPropSymbols$u = Object.getOwnPropertySymbols; + var __hasOwnProp$u = Object.prototype.hasOwnProperty; + var __propIsEnum$u = Object.prototype.propertyIsEnumerable; + var __defNormalProp$u = (obj, key, value) => key in obj ? __defProp$u(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$u = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$u.call(b, prop)) + __defNormalProp$u(a, prop, b[prop]); + if (__getOwnPropSymbols$u) + for (var prop of __getOwnPropSymbols$u(b)) { + if (__propIsEnum$u.call(b, prop)) + __defNormalProp$u(a, prop, b[prop]); + } + return a; + }; + class BlendModeFilter extends Filter { + constructor(options) { + const gpuOptions = options.gpu; + const gpuSource = compileBlendModeShader(__spreadValues$u({ source: blendTemplate }, gpuOptions)); + const gpuProgram = GpuProgram.from({ + vertex: { + source: gpuSource, + entryPoint: "mainVertex" + }, + fragment: { + source: gpuSource, + entryPoint: "mainFragment" + } + }); + const glOptions = options.gl; + const glSource = compileBlendModeShader(__spreadValues$u({ source: blendTemplateFrag }, glOptions)); + const glProgram = GlProgram.from({ + vertex: blendTemplateVert, + fragment: glSource + }); + const uniformGroup = new UniformGroup({ + uBlend: { + value: 1, + type: "f32" + } + }); + super({ + gpuProgram, + glProgram, + blendRequired: true, + resources: { + blendUniforms: uniformGroup, + uBackTexture: Texture.EMPTY + } + }); + } + } + function compileBlendModeShader(options) { + const { source, functions, main } = options; + return source.replace("{FUNCTIONS}", functions).replace("{MAIN}", main); + } + + "use strict"; + const hslgl = ` + float getLuminosity(vec3 c) { + return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; + } + + vec3 setLuminosity(vec3 c, float lum) { + float modLum = lum - getLuminosity(c); + vec3 color = c.rgb + vec3(modLum); + + // clip back into legal range + modLum = getLuminosity(color); + vec3 modLumVec = vec3(modLum); + + float cMin = min(color.r, min(color.g, color.b)); + float cMax = max(color.r, max(color.g, color.b)); + + if(cMin < 0.0) { + color = mix(modLumVec, color, modLum / (modLum - cMin)); + } + + if(cMax > 1.0) { + color = mix(modLumVec, color, (1.0 - modLum) / (cMax - modLum)); + } + + return color; + } + + float getSaturation(vec3 c) { + return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); + } + + vec3 setSaturationMinMidMax(vec3 cSorted, float s) { + vec3 colorSorted = cSorted; + + if(colorSorted.z > colorSorted.x) { + colorSorted.y = (((colorSorted.y - colorSorted.x) * s) / (colorSorted.z - colorSorted.x)); + colorSorted.z = s; + } + else { + colorSorted.y = 0.0; + colorSorted.z = 0.0; + } + + colorSorted.x = 0.0; + + return colorSorted; + } + + vec3 setSaturation(vec3 c, float s) { + vec3 color = c; + + if(color.r <= color.g && color.r <= color.b) { + if(color.g <= color.b) { + color = setSaturationMinMidMax(color.rgb, s).rgb; + } + else { + color = setSaturationMinMidMax(color.rbg, s).rbg; + } + } + else if(color.g <= color.r && color.g <= color.b) { + if(color.r <= color.b) { + color = setSaturationMinMidMax(color.grb, s).grb; + } + else { + color = setSaturationMinMidMax(color.gbr, s).gbr; + } + } + else { + // Using bgr for both fixes part of hue + if(color.r <= color.g) { + color = setSaturationMinMidMax(color.brg, s).brg; + } + else { + color = setSaturationMinMidMax(color.bgr, s).bgr; + } + } + + return color; + } + `; + + "use strict"; + const hslgpu = ` + fn getLuminosity(c: vec3) -> f32 + { + return 0.3*c.r + 0.59*c.g + 0.11*c.b; + } + + fn setLuminosity(c: vec3, lum: f32) -> vec3 + { + var modLum: f32 = lum - getLuminosity(c); + var color: vec3 = c.rgb + modLum; + + // clip back into legal range + modLum = getLuminosity(color); + let modLumVec = vec3(modLum); + + let cMin: f32 = min(color.r, min(color.g, color.b)); + let cMax: f32 = max(color.r, max(color.g, color.b)); + + if(cMin < 0.0) + { + color = mix(modLumVec, color, modLum / (modLum - cMin)); + } + + if(cMax > 1.0) + { + color = mix(modLumVec, color, (1 - modLum) / (cMax - modLum)); + } + + return color; + } + + fn getSaturation(c: vec3) -> f32 + { + return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); + } + + fn setSaturationMinMidMax(cSorted: vec3, s: f32) -> vec3 + { + var colorSorted = cSorted; + + if(colorSorted.z > colorSorted.x) + { + colorSorted.y = (((colorSorted.y - colorSorted.x) * s) / (colorSorted.z - colorSorted.x)); + colorSorted.z = s; + } + else + { + colorSorted.y = 0; + colorSorted.z = 0; + } + + colorSorted.x = 0; + + return colorSorted; + } + + fn setSaturation(c: vec3, s: f32) -> vec3 + { + var color = c; + + if (color.r <= color.g && color.r <= color.b) + { + if (color.g <= color.b) + { + color = vec3(setSaturationMinMidMax(color.rgb, s)).rgb; + } + else + { + color = vec3(setSaturationMinMidMax(color.rbg, s)).rbg; + } + } + else if (color.g <= color.r && color.g <= color.b) + { + if (color.r <= color.b) + { + color = vec3(setSaturationMinMidMax(color.grb, s)).grb; + } + else + { + color = vec3(setSaturationMinMidMax(color.gbr, s)).gbr; + } + } + else + { + // Using bgr for both fixes part of hue + if (color.r <= color.g) + { + color = vec3(setSaturationMinMidMax(color.brg, s)).brg; + } + else + { + color = vec3(setSaturationMinMidMax(color.bgr, s)).bgr; + } + } + + return color; + } + `; + + var vertex$2 = "in vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n \n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n"; + + var fragment$4 = "\nin vec2 vTextureCoord;\n\nout vec4 finalColor;\n\nuniform float uAlpha;\nuniform sampler2D uTexture;\n\nvoid main()\n{\n finalColor = texture(uTexture, vTextureCoord) * uAlpha;\n}\n"; + + var source$5 = "struct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct AlphaUniforms {\n uAlpha:f32,\n};\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var alphaUniforms : AlphaUniforms;\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2\n{\n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition)\n );\n}\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2,\n @builtin(position) position: vec4\n) -> @location(0) vec4 {\n \n var sample = textureSample(uTexture, uSampler, uv);\n \n return sample * alphaUniforms.uAlpha;\n}"; + + "use strict"; + var __defProp$t = Object.defineProperty; + var __defProps$e = Object.defineProperties; + var __getOwnPropDescs$e = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$t = Object.getOwnPropertySymbols; + var __hasOwnProp$t = Object.prototype.hasOwnProperty; + var __propIsEnum$t = Object.prototype.propertyIsEnumerable; + var __defNormalProp$t = (obj, key, value) => key in obj ? __defProp$t(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$t = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$t.call(b, prop)) + __defNormalProp$t(a, prop, b[prop]); + if (__getOwnPropSymbols$t) + for (var prop of __getOwnPropSymbols$t(b)) { + if (__propIsEnum$t.call(b, prop)) + __defNormalProp$t(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$e = (a, b) => __defProps$e(a, __getOwnPropDescs$e(b)); + var __objRest$c = (source2, exclude) => { + var target = {}; + for (var prop in source2) + if (__hasOwnProp$t.call(source2, prop) && exclude.indexOf(prop) < 0) + target[prop] = source2[prop]; + if (source2 != null && __getOwnPropSymbols$t) + for (var prop of __getOwnPropSymbols$t(source2)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$t.call(source2, prop)) + target[prop] = source2[prop]; + } + return target; + }; + const _AlphaFilter = class _AlphaFilter extends Filter { + constructor(options) { + options = __spreadValues$t(__spreadValues$t({}, _AlphaFilter.defaultOptions), options); + const gpuProgram = GpuProgram.from({ + vertex: { + source: source$5, + entryPoint: "mainVertex" + }, + fragment: { + source: source$5, + entryPoint: "mainFragment" + } + }); + const glProgram = GlProgram.from({ + vertex: vertex$2, + fragment: fragment$4, + name: "alpha-filter" + }); + const _a = options, { alpha } = _a, rest = __objRest$c(_a, ["alpha"]); + const alphaUniforms = new UniformGroup({ + uAlpha: { value: alpha, type: "f32" } + }); + super(__spreadProps$e(__spreadValues$t({}, rest), { + gpuProgram, + glProgram, + resources: { + alphaUniforms + } + })); + } + /** + * Coefficient for alpha multiplication + * @default 1 + */ + get alpha() { + return this.resources.alphaUniforms.uniforms.uAlpha; + } + set alpha(value) { + this.resources.alphaUniforms.uniforms.uAlpha = value; + } + }; + /** Default filter options */ + _AlphaFilter.defaultOptions = { + /** Amount of alpha from 0 to 1, where 0 is transparent */ + alpha: 1 + }; + let AlphaFilter = _AlphaFilter; + + "use strict"; + const GAUSSIAN_VALUES = { + 5: [0.153388, 0.221461, 0.250301], + 7: [0.071303, 0.131514, 0.189879, 0.214607], + 9: [0.028532, 0.067234, 0.124009, 0.179044, 0.20236], + 11: [93e-4, 0.028002, 0.065984, 0.121703, 0.175713, 0.198596], + 13: [2406e-6, 9255e-6, 0.027867, 0.065666, 0.121117, 0.174868, 0.197641], + 15: [489e-6, 2403e-6, 9246e-6, 0.02784, 0.065602, 0.120999, 0.174697, 0.197448] + }; + + "use strict"; + const fragTemplate = [ + "in vec2 vBlurTexCoords[%size%];", + "uniform sampler2D uTexture;", + "out vec4 finalColor;", + "void main(void)", + "{", + " finalColor = vec4(0.0);", + " %blur%", + "}" + ].join("\n"); + function generateBlurFragSource(kernelSize) { + const kernel = GAUSSIAN_VALUES[kernelSize]; + const halfLength = kernel.length; + let fragSource = fragTemplate; + let blurLoop = ""; + const template = "finalColor += texture(uTexture, vBlurTexCoords[%index%]) * %value%;"; + let value; + for (let i = 0; i < kernelSize; i++) { + let blur = template.replace("%index%", i.toString()); + value = i; + if (i >= halfLength) { + value = kernelSize - i - 1; + } + blur = blur.replace("%value%", kernel[value].toString()); + blurLoop += blur; + blurLoop += "\n"; + } + fragSource = fragSource.replace("%blur%", blurLoop); + fragSource = fragSource.replace("%size%", kernelSize.toString()); + return fragSource; + } + + "use strict"; + const vertTemplate = ` + in vec2 aPosition; + + uniform float uStrength; + + out vec2 vBlurTexCoords[%size%]; + + uniform vec4 uInputSize; + uniform vec4 uOutputFrame; + uniform vec4 uOutputTexture; + + vec4 filterVertexPosition( void ) +{ + vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy; + + position.x = position.x * (2.0 / uOutputTexture.x) - 1.0; + position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z; + + return vec4(position, 0.0, 1.0); +} + + vec2 filterTextureCoord( void ) + { + return aPosition * (uOutputFrame.zw * uInputSize.zw); + } + + void main(void) + { + gl_Position = filterVertexPosition(); + + float pixelStrength = uInputSize.%dimension% * uStrength; + + vec2 textureCoord = filterTextureCoord(); + %blur% + }`; + function generateBlurVertSource(kernelSize, x) { + const halfLength = Math.ceil(kernelSize / 2); + let vertSource = vertTemplate; + let blurLoop = ""; + let template; + if (x) { + template = "vBlurTexCoords[%index%] = textureCoord + vec2(%sampleIndex% * pixelStrength, 0.0);"; + } else { + template = "vBlurTexCoords[%index%] = textureCoord + vec2(0.0, %sampleIndex% * pixelStrength);"; + } + for (let i = 0; i < kernelSize; i++) { + let blur = template.replace("%index%", i.toString()); + blur = blur.replace("%sampleIndex%", `${i - (halfLength - 1)}.0`); + blurLoop += blur; + blurLoop += "\n"; + } + vertSource = vertSource.replace("%blur%", blurLoop); + vertSource = vertSource.replace("%size%", kernelSize.toString()); + vertSource = vertSource.replace("%dimension%", x ? "z" : "w"); + return vertSource; + } + + "use strict"; + function generateBlurGlProgram(horizontal, kernelSize) { + const vertex = generateBlurVertSource(kernelSize, horizontal); + const fragment = generateBlurFragSource(kernelSize); + return GlProgram.from({ + vertex, + fragment, + name: `blur-${horizontal ? "horizontal" : "vertical"}-pass-filter` + }); + } + + var source$4 = "\n\nstruct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct BlurUniforms {\n uStrength:f32,\n};\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var blurUniforms : BlurUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n %blur-struct%\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2\n{\n return gfu.uGlobalFrame.zw;\n}\n\n\n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n\n let filteredCord = filterTextureCoord(aPosition);\n\n let strength = gfu.uInputSize.w * blurUniforms.uStrength;\n\n return VSOutput(\n filterVertexPosition(aPosition),\n %blur-vertex-out%\n );\n}\n\n@fragment\nfn mainFragment(\n @builtin(position) position: vec4,\n %blur-fragment-in%\n) -> @location(0) vec4 {\n\n var finalColor = vec4(0.0);\n\n %blur-sampling%\n\n return finalColor;\n}"; + + "use strict"; + function generateBlurProgram(horizontal, kernelSize) { + const kernel = GAUSSIAN_VALUES[kernelSize]; + const halfLength = kernel.length; + const blurStructSource = []; + const blurOutSource = []; + const blurSamplingSource = []; + for (let i = 0; i < kernelSize; i++) { + blurStructSource[i] = `@location(${i}) offset${i}: vec2,`; + if (horizontal) { + blurOutSource[i] = `filteredCord + vec2(${i - halfLength + 1} * strength, 0.0),`; + } else { + blurOutSource[i] = `filteredCord + vec2(0.0, ${i - halfLength + 1} * strength),`; + } + const kernelIndex = i < halfLength ? i : kernelSize - i - 1; + const kernelValue = kernel[kernelIndex].toString(); + blurSamplingSource[i] = `finalColor += textureSample(uTexture, uSampler, offset${i}) * ${kernelValue};`; + } + const blurStruct = blurStructSource.join("\n"); + const blurOut = blurOutSource.join("\n"); + const blurSampling = blurSamplingSource.join("\n"); + const finalSource = source$4.replace("%blur-struct%", blurStruct).replace("%blur-vertex-out%", blurOut).replace("%blur-fragment-in%", blurStruct).replace("%blur-sampling%", blurSampling); + return GpuProgram.from({ + vertex: { + source: finalSource, + entryPoint: "mainVertex" + }, + fragment: { + source: finalSource, + entryPoint: "mainFragment" + } + }); + } + + "use strict"; + var __defProp$s = Object.defineProperty; + var __getOwnPropSymbols$s = Object.getOwnPropertySymbols; + var __hasOwnProp$s = Object.prototype.hasOwnProperty; + var __propIsEnum$s = Object.prototype.propertyIsEnumerable; + var __defNormalProp$s = (obj, key, value) => key in obj ? __defProp$s(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$s = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$s.call(b, prop)) + __defNormalProp$s(a, prop, b[prop]); + if (__getOwnPropSymbols$s) + for (var prop of __getOwnPropSymbols$s(b)) { + if (__propIsEnum$s.call(b, prop)) + __defNormalProp$s(a, prop, b[prop]); + } + return a; + }; + const _BlurFilterPass = class _BlurFilterPass extends Filter { + /** + * @param options + * @param options.horizontal - Do pass along the x-axis (`true`) or y-axis (`false`). + * @param options.strength - The strength of the blur filter. + * @param options.quality - The quality of the blur filter. + * @param options.kernelSize - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. + */ + constructor(options) { + options = __spreadValues$s(__spreadValues$s({}, _BlurFilterPass.defaultOptions), options); + const glProgram = generateBlurGlProgram(options.horizontal, options.kernelSize); + const gpuProgram = generateBlurProgram(options.horizontal, options.kernelSize); + super(__spreadValues$s({ + glProgram, + gpuProgram, + resources: { + blurUniforms: { + uStrength: { value: 0, type: "f32" } + } + } + }, options)); + this.horizontal = options.horizontal; + this._quality = 0; + this.quality = options.quality; + this.blur = options.strength; + this._uniforms = this.resources.blurUniforms.uniforms; + } + /** + * Applies the filter. + * @param filterManager - The manager. + * @param input - The input target. + * @param output - The output target. + * @param clearMode - How to clear + */ + apply(filterManager, input, output, clearMode) { + this._uniforms.uStrength = this.strength / this.passes; + if (this.passes === 1) { + filterManager.applyFilter(this, input, output, clearMode); + } else { + const tempTexture = TexturePool.getSameSizeTexture(input); + let flip = input; + let flop = tempTexture; + this._state.blend = false; + for (let i = 0; i < this.passes - 1; i++) { + filterManager.applyFilter(this, flip, flop, filterManager.renderer.type === RendererType.WEBGPU); + const temp = flop; + flop = flip; + flip = temp; + } + this._state.blend = true; + filterManager.applyFilter(this, flip, output, clearMode); + TexturePool.returnTexture(tempTexture); + } + } + /** + * Sets the strength of both the blur. + * @default 16 + */ + get blur() { + return this.strength; + } + set blur(value) { + this.padding = 1 + Math.abs(value) * 2; + this.strength = value; + } + /** + * Sets the quality of the blur by modifying the number of passes. More passes means higher + * quality blurring but the lower the performance. + * @default 4 + */ + get quality() { + return this._quality; + } + set quality(value) { + this._quality = value; + this.passes = value; + } + }; + /** Default blur filter pass options */ + _BlurFilterPass.defaultOptions = { + /** The strength of the blur filter. */ + strength: 8, + /** The quality of the blur filter. */ + quality: 4, + /** The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ + kernelSize: 5 + }; + let BlurFilterPass = _BlurFilterPass; + + "use strict"; + var __defProp$r = Object.defineProperty; + var __defProps$d = Object.defineProperties; + var __getOwnPropDescs$d = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$r = Object.getOwnPropertySymbols; + var __hasOwnProp$r = Object.prototype.hasOwnProperty; + var __propIsEnum$r = Object.prototype.propertyIsEnumerable; + var __defNormalProp$r = (obj, key, value) => key in obj ? __defProp$r(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$r = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$r.call(b, prop)) + __defNormalProp$r(a, prop, b[prop]); + if (__getOwnPropSymbols$r) + for (var prop of __getOwnPropSymbols$r(b)) { + if (__propIsEnum$r.call(b, prop)) + __defNormalProp$r(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$d = (a, b) => __defProps$d(a, __getOwnPropDescs$d(b)); + var __objRest$b = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$r.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$r) + for (var prop of __getOwnPropSymbols$r(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$r.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class BlurFilter extends Filter { + constructor(...args) { + var _a; + let options = (_a = args[0]) != null ? _a : {}; + if (typeof options === "number") { + deprecation(v8_0_0, "BlurFilter constructor params are now options object. See params: { strength, quality, resolution, kernelSize }"); + options = { strength: options }; + if (args[1]) + options.quality = args[1]; + if (args[2]) + options.resolution = args[2]; + if (args[3]) + options.kernelSize = args[3]; + } + options = __spreadValues$r(__spreadValues$r({}, BlurFilterPass.defaultOptions), options); + const _b = options, { strength, quality } = _b, rest = __objRest$b(_b, ["strength", "quality"]); + super(__spreadProps$d(__spreadValues$r({}, rest), { + compatibleRenderers: RendererType.BOTH, + resources: {} + })); + this._repeatEdgePixels = false; + this.blurXFilter = new BlurFilterPass(__spreadValues$r({ horizontal: false }, options)); + this.blurYFilter = new BlurFilterPass(__spreadValues$r({ horizontal: true }, options)); + this.quality = quality; + this.blur = strength; + this.repeatEdgePixels = false; + } + /** + * Applies the filter. + * @param filterManager - The manager. + * @param input - The input target. + * @param output - The output target. + * @param clearMode - How to clear + */ + apply(filterManager, input, output, clearMode) { + const xStrength = Math.abs(this.blurXFilter.strength); + const yStrength = Math.abs(this.blurYFilter.strength); + if (xStrength && yStrength) { + const tempTexture = TexturePool.getSameSizeTexture(input); + this.blurXFilter.apply(filterManager, input, tempTexture, true); + this.blurYFilter.apply(filterManager, tempTexture, output, clearMode); + TexturePool.returnTexture(tempTexture); + } else if (yStrength) { + this.blurYFilter.apply(filterManager, input, output, clearMode); + } else { + this.blurXFilter.apply(filterManager, input, output, clearMode); + } + } + updatePadding() { + if (this._repeatEdgePixels) { + this.padding = 0; + } else { + this.padding = Math.max(Math.abs(this.blurXFilter.blur), Math.abs(this.blurYFilter.blur)) * 2; + } + } + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * @default 2 + */ + get blur() { + return this.blurXFilter.blur; + } + set blur(value) { + this.blurXFilter.blur = this.blurYFilter.blur = value; + this.updatePadding(); + } + /** + * Sets the number of passes for blur. More passes means higher quality bluring. + * @default 1 + */ + get quality() { + return this.blurXFilter.quality; + } + set quality(value) { + this.blurXFilter.quality = this.blurYFilter.quality = value; + } + /** + * Sets the strength of the blurX property + * @default 2 + */ + get blurX() { + return this.blurXFilter.blur; + } + set blurX(value) { + this.blurXFilter.blur = value; + this.updatePadding(); + } + /** + * Sets the strength of the blurY property + * @default 2 + */ + get blurY() { + return this.blurYFilter.blur; + } + set blurY(value) { + this.blurYFilter.blur = value; + this.updatePadding(); + } + /** + * Sets the blendmode of the filter + * @default "normal" + */ + get blendMode() { + return this.blurYFilter.blendMode; + } + set blendMode(value) { + this.blurYFilter.blendMode = value; + } + /** + * If set to true the edge of the target will be clamped + * @default false + */ + get repeatEdgePixels() { + return this._repeatEdgePixels; + } + set repeatEdgePixels(value) { + this._repeatEdgePixels = value; + this.updatePadding(); + } + } + /** Default blur filter options */ + BlurFilter.defaultOptions = { + /** The strength of the blur filter. */ + strength: 8, + /** The quality of the blur filter. */ + quality: 4, + /** The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ + kernelSize: 5 + }; + + var fragment$3 = "\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nout vec4 finalColor;\n\nuniform float uColorMatrix[20];\nuniform float uAlpha;\n\nuniform sampler2D uTexture;\n\nfloat rand(vec2 co)\n{\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main()\n{\n vec4 color = texture(uTexture, vTextureCoord);\n float randomValue = rand(gl_FragCoord.xy * 0.2);\n float diff = (randomValue - 0.5) * 0.5;\n\n if (uAlpha == 0.0) {\n finalColor = color;\n return;\n }\n\n if (color.a > 0.0) {\n color.rgb /= color.a;\n }\n\n vec4 result;\n\n result.r = (uColorMatrix[0] * color.r);\n result.r += (uColorMatrix[1] * color.g);\n result.r += (uColorMatrix[2] * color.b);\n result.r += (uColorMatrix[3] * color.a);\n result.r += uColorMatrix[4];\n\n result.g = (uColorMatrix[5] * color.r);\n result.g += (uColorMatrix[6] * color.g);\n result.g += (uColorMatrix[7] * color.b);\n result.g += (uColorMatrix[8] * color.a);\n result.g += uColorMatrix[9];\n\n result.b = (uColorMatrix[10] * color.r);\n result.b += (uColorMatrix[11] * color.g);\n result.b += (uColorMatrix[12] * color.b);\n result.b += (uColorMatrix[13] * color.a);\n result.b += uColorMatrix[14];\n\n result.a = (uColorMatrix[15] * color.r);\n result.a += (uColorMatrix[16] * color.g);\n result.a += (uColorMatrix[17] * color.b);\n result.a += (uColorMatrix[18] * color.a);\n result.a += uColorMatrix[19];\n\n vec3 rgb = mix(color.rgb, result.rgb, uAlpha);\n\n // Premultiply alpha again.\n rgb *= result.a;\n\n finalColor = vec4(rgb, result.a);\n}\n"; + + var source$3 = "struct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct ColorMatrixUniforms {\n uColorMatrix:array, 5>,\n uAlpha:f32,\n};\n\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n@group(1) @binding(0) var colorMatrixUniforms : ColorMatrixUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2,\n };\n \nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition),\n );\n}\n\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2,\n) -> @location(0) vec4 {\n\n\n var c = textureSample(uTexture, uSampler, uv);\n \n if (colorMatrixUniforms.uAlpha == 0.0) {\n return c;\n }\n\n \n // Un-premultiply alpha before applying the color matrix. See issue #3539.\n if (c.a > 0.0) {\n c.r /= c.a;\n c.g /= c.a;\n c.b /= c.a;\n }\n\n var cm = colorMatrixUniforms.uColorMatrix;\n\n\n var result = vec4(0.);\n\n result.r = (cm[0][0] * c.r);\n result.r += (cm[0][1] * c.g);\n result.r += (cm[0][2] * c.b);\n result.r += (cm[0][3] * c.a);\n result.r += cm[1][0];\n\n result.g = (cm[1][1] * c.r);\n result.g += (cm[1][2] * c.g);\n result.g += (cm[1][3] * c.b);\n result.g += (cm[2][0] * c.a);\n result.g += cm[2][1];\n\n result.b = (cm[2][2] * c.r);\n result.b += (cm[2][3] * c.g);\n result.b += (cm[3][0] * c.b);\n result.b += (cm[3][1] * c.a);\n result.b += cm[3][2];\n\n result.a = (cm[3][3] * c.r);\n result.a += (cm[4][0] * c.g);\n result.a += (cm[4][1] * c.b);\n result.a += (cm[4][2] * c.a);\n result.a += cm[4][3];\n\n var rgb = mix(c.rgb, result.rgb, colorMatrixUniforms.uAlpha);\n\n rgb.r *= result.a;\n rgb.g *= result.a;\n rgb.b *= result.a;\n\n return vec4(rgb, result.a);\n}"; + + "use strict"; + var __defProp$q = Object.defineProperty; + var __defProps$c = Object.defineProperties; + var __getOwnPropDescs$c = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$q = Object.getOwnPropertySymbols; + var __hasOwnProp$q = Object.prototype.hasOwnProperty; + var __propIsEnum$q = Object.prototype.propertyIsEnumerable; + var __defNormalProp$q = (obj, key, value) => key in obj ? __defProp$q(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$q = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$q.call(b, prop)) + __defNormalProp$q(a, prop, b[prop]); + if (__getOwnPropSymbols$q) + for (var prop of __getOwnPropSymbols$q(b)) { + if (__propIsEnum$q.call(b, prop)) + __defNormalProp$q(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$c = (a, b) => __defProps$c(a, __getOwnPropDescs$c(b)); + class ColorMatrixFilter extends Filter { + constructor(options = {}) { + const colorMatrixUniforms = new UniformGroup({ + uColorMatrix: { + value: [ + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ], + type: "f32", + size: 20 + }, + uAlpha: { + value: 1, + type: "f32" + } + }); + const gpuProgram = GpuProgram.from({ + vertex: { + source: source$3, + entryPoint: "mainVertex" + }, + fragment: { + source: source$3, + entryPoint: "mainFragment" + } + }); + const glProgram = GlProgram.from({ + vertex: vertex$2, + fragment: fragment$3, + name: "color-matrix-filter" + }); + super(__spreadProps$c(__spreadValues$q({}, options), { + gpuProgram, + glProgram, + resources: { + colorMatrixUniforms + } + })); + this.alpha = 1; + } + /** + * Transforms current matrix and set the new one + * @param {number[]} matrix - 5x4 matrix + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + _loadMatrix(matrix, multiply = false) { + let newMatrix = matrix; + if (multiply) { + this._multiply(newMatrix, this.matrix, matrix); + newMatrix = this._colorMatrix(newMatrix); + } + this.resources.colorMatrixUniforms.uniforms.uColorMatrix = newMatrix; + this.resources.colorMatrixUniforms.update(); + } + /** + * Multiplies two mat5's + * @private + * @param out - 5x4 matrix the receiving matrix + * @param a - 5x4 matrix the first operand + * @param b - 5x4 matrix the second operand + * @returns {number[]} 5x4 matrix + */ + _multiply(out, a, b) { + out[0] = a[0] * b[0] + a[1] * b[5] + a[2] * b[10] + a[3] * b[15]; + out[1] = a[0] * b[1] + a[1] * b[6] + a[2] * b[11] + a[3] * b[16]; + out[2] = a[0] * b[2] + a[1] * b[7] + a[2] * b[12] + a[3] * b[17]; + out[3] = a[0] * b[3] + a[1] * b[8] + a[2] * b[13] + a[3] * b[18]; + out[4] = a[0] * b[4] + a[1] * b[9] + a[2] * b[14] + a[3] * b[19] + a[4]; + out[5] = a[5] * b[0] + a[6] * b[5] + a[7] * b[10] + a[8] * b[15]; + out[6] = a[5] * b[1] + a[6] * b[6] + a[7] * b[11] + a[8] * b[16]; + out[7] = a[5] * b[2] + a[6] * b[7] + a[7] * b[12] + a[8] * b[17]; + out[8] = a[5] * b[3] + a[6] * b[8] + a[7] * b[13] + a[8] * b[18]; + out[9] = a[5] * b[4] + a[6] * b[9] + a[7] * b[14] + a[8] * b[19] + a[9]; + out[10] = a[10] * b[0] + a[11] * b[5] + a[12] * b[10] + a[13] * b[15]; + out[11] = a[10] * b[1] + a[11] * b[6] + a[12] * b[11] + a[13] * b[16]; + out[12] = a[10] * b[2] + a[11] * b[7] + a[12] * b[12] + a[13] * b[17]; + out[13] = a[10] * b[3] + a[11] * b[8] + a[12] * b[13] + a[13] * b[18]; + out[14] = a[10] * b[4] + a[11] * b[9] + a[12] * b[14] + a[13] * b[19] + a[14]; + out[15] = a[15] * b[0] + a[16] * b[5] + a[17] * b[10] + a[18] * b[15]; + out[16] = a[15] * b[1] + a[16] * b[6] + a[17] * b[11] + a[18] * b[16]; + out[17] = a[15] * b[2] + a[16] * b[7] + a[17] * b[12] + a[18] * b[17]; + out[18] = a[15] * b[3] + a[16] * b[8] + a[17] * b[13] + a[18] * b[18]; + out[19] = a[15] * b[4] + a[16] * b[9] + a[17] * b[14] + a[18] * b[19] + a[19]; + return out; + } + /** + * Create a Float32 Array and normalize the offset component to 0-1 + * @param {number[]} matrix - 5x4 matrix + * @returns {number[]} 5x4 matrix with all values between 0-1 + */ + _colorMatrix(matrix) { + const m = new Float32Array(matrix); + m[4] /= 255; + m[9] /= 255; + m[14] /= 255; + m[19] /= 255; + return m; + } + /** + * Adjusts brightness + * @param b - value of the brigthness (0-1, where 0 is black) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + brightness(b, multiply) { + const matrix = [ + b, + 0, + 0, + 0, + 0, + 0, + b, + 0, + 0, + 0, + 0, + 0, + b, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Sets each channel on the diagonal of the color matrix. + * This can be used to achieve a tinting effect on Containers similar to the tint field of some + * display objects like Sprite, Text, Graphics, and Mesh. + * @param color - Color of the tint. This is a hex value. + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + tint(color, multiply) { + const [r, g, b] = Color.shared.setValue(color).toArray(); + const matrix = [ + r, + 0, + 0, + 0, + 0, + 0, + g, + 0, + 0, + 0, + 0, + 0, + b, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Set the matrices in grey scales + * @param scale - value of the grey (0-1, where 0 is black) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + greyscale(scale, multiply) { + const matrix = [ + scale, + scale, + scale, + 0, + 0, + scale, + scale, + scale, + 0, + 0, + scale, + scale, + scale, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * for our american friends! + * @param scale + * @param multiply + */ + grayscale(scale, multiply) { + this.greyscale(scale, multiply); + } + /** + * Set the black and white matrice. + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + blackAndWhite(multiply) { + const matrix = [ + 0.3, + 0.6, + 0.1, + 0, + 0, + 0.3, + 0.6, + 0.1, + 0, + 0, + 0.3, + 0.6, + 0.1, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Set the hue property of the color + * @param rotation - in degrees + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + hue(rotation, multiply) { + rotation = (rotation || 0) / 180 * Math.PI; + const cosR = Math.cos(rotation); + const sinR = Math.sin(rotation); + const sqrt = Math.sqrt; + const w = 1 / 3; + const sqrW = sqrt(w); + const a00 = cosR + (1 - cosR) * w; + const a01 = w * (1 - cosR) - sqrW * sinR; + const a02 = w * (1 - cosR) + sqrW * sinR; + const a10 = w * (1 - cosR) + sqrW * sinR; + const a11 = cosR + w * (1 - cosR); + const a12 = w * (1 - cosR) - sqrW * sinR; + const a20 = w * (1 - cosR) - sqrW * sinR; + const a21 = w * (1 - cosR) + sqrW * sinR; + const a22 = cosR + w * (1 - cosR); + const matrix = [ + a00, + a01, + a02, + 0, + 0, + a10, + a11, + a12, + 0, + 0, + a20, + a21, + a22, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Set the contrast matrix, increase the separation between dark and bright + * Increase contrast : shadows darker and highlights brighter + * Decrease contrast : bring the shadows up and the highlights down + * @param amount - value of the contrast (0-1) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + contrast(amount, multiply) { + const v = (amount || 0) + 1; + const o = -0.5 * (v - 1); + const matrix = [ + v, + 0, + 0, + 0, + o, + 0, + v, + 0, + 0, + o, + 0, + 0, + v, + 0, + o, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Set the saturation matrix, increase the separation between colors + * Increase saturation : increase contrast, brightness, and sharpness + * @param amount - The saturation amount (0-1) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + saturate(amount = 0, multiply) { + const x = amount * 2 / 3 + 1; + const y = (x - 1) * -0.5; + const matrix = [ + x, + y, + y, + 0, + 0, + y, + x, + y, + 0, + 0, + y, + y, + x, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** Desaturate image (remove color) Call the saturate function */ + desaturate() { + this.saturate(-1); + } + /** + * Negative image (inverse of classic rgb matrix) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + negative(multiply) { + const matrix = [ + -1, + 0, + 0, + 1, + 0, + 0, + -1, + 0, + 1, + 0, + 0, + 0, + -1, + 1, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Sepia image + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + sepia(multiply) { + const matrix = [ + 0.393, + 0.7689999, + 0.18899999, + 0, + 0, + 0.349, + 0.6859999, + 0.16799999, + 0, + 0, + 0.272, + 0.5339999, + 0.13099999, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Color motion picture process invented in 1916 (thanks Dominic Szablewski) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + technicolor(multiply) { + const matrix = [ + 1.9125277891456083, + -0.8545344976951645, + -0.09155508482755585, + 0, + 11.793603434377337, + -0.3087833385928097, + 1.7658908555458428, + -0.10601743074722245, + 0, + -70.35205161461398, + -0.231103377548616, + -0.7501899197440212, + 1.847597816108189, + 0, + 30.950940869491138, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Polaroid filter + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + polaroid(multiply) { + const matrix = [ + 1.438, + -0.062, + -0.062, + 0, + 0, + -0.122, + 1.378, + -0.122, + 0, + 0, + -0.016, + -0.016, + 1.483, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Filter who transforms : Red -> Blue and Blue -> Red + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + toBGR(multiply) { + const matrix = [ + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Color reversal film introduced by Eastman Kodak in 1935. (thanks Dominic Szablewski) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + kodachrome(multiply) { + const matrix = [ + 1.1285582396593525, + -0.3967382283601348, + -0.03992559172921793, + 0, + 63.72958762196502, + -0.16404339962244616, + 1.0835251566291304, + -0.05498805115633132, + 0, + 24.732407896706203, + -0.16786010706155763, + -0.5603416277695248, + 1.6014850761964943, + 0, + 35.62982807460946, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Brown delicious browni filter (thanks Dominic Szablewski) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + browni(multiply) { + const matrix = [ + 0.5997023498159715, + 0.34553243048391263, + -0.2708298674538042, + 0, + 47.43192855600873, + -0.037703249837783157, + 0.8609577587992641, + 0.15059552388459913, + 0, + -36.96841498319127, + 0.24113635128153335, + -0.07441037908422492, + 0.44972182064877153, + 0, + -7.562075277591283, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Vintage filter (thanks Dominic Szablewski) + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + vintage(multiply) { + const matrix = [ + 0.6279345635605994, + 0.3202183420819367, + -0.03965408211312453, + 0, + 9.651285835294123, + 0.02578397704808868, + 0.6441188644374771, + 0.03259127616149294, + 0, + 7.462829176470591, + 0.0466055556782719, + -0.0851232987247891, + 0.5241648018700465, + 0, + 5.159190588235296, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * We don't know exactly what it does, kind of gradient map, but funny to play with! + * @param desaturation - Tone values. + * @param toned - Tone values. + * @param lightColor - Tone values, example: `0xFFE580` + * @param darkColor - Tone values, example: `0xFFE580` + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + colorTone(desaturation, toned, lightColor, darkColor, multiply) { + desaturation = desaturation || 0.2; + toned = toned || 0.15; + lightColor = lightColor || 16770432; + darkColor = darkColor || 3375104; + const temp = Color.shared; + const [lR, lG, lB] = temp.setValue(lightColor).toArray(); + const [dR, dG, dB] = temp.setValue(darkColor).toArray(); + const matrix = [ + 0.3, + 0.59, + 0.11, + 0, + 0, + lR, + lG, + lB, + desaturation, + 0, + dR, + dG, + dB, + toned, + 0, + lR - dR, + lG - dG, + lB - dB, + 0, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Night effect + * @param intensity - The intensity of the night effect. + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + night(intensity, multiply) { + intensity = intensity || 0.1; + const matrix = [ + intensity * -2, + -intensity, + 0, + 0, + 0, + -intensity, + 0, + intensity, + 0, + 0, + 0, + intensity, + intensity * 2, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * Predator effect + * + * Erase the current matrix by setting a new indepent one + * @param amount - how much the predator feels his future victim + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + predator(amount, multiply) { + const matrix = [ + // row 1 + 11.224130630493164 * amount, + -4.794486999511719 * amount, + -2.8746118545532227 * amount, + 0 * amount, + 0.40342438220977783 * amount, + // row 2 + -3.6330697536468506 * amount, + 9.193157196044922 * amount, + -2.951810836791992 * amount, + 0 * amount, + -1.316135048866272 * amount, + // row 3 + -3.2184197902679443 * amount, + -4.2375030517578125 * amount, + 7.476448059082031 * amount, + 0 * amount, + 0.8044459223747253 * amount, + // row 4 + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** + * LSD effect + * + * Multiply the current matrix + * @param multiply - if true, current matrix and matrix are multiplied. If false, + * just set the current matrix with @param matrix + */ + lsd(multiply) { + const matrix = [ + 2, + -0.4, + 0.5, + 0, + 0, + -0.5, + 2, + -0.4, + 0, + 0, + -0.4, + -0.5, + 3, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, multiply); + } + /** Erase the current matrix by setting the default one. */ + reset() { + const matrix = [ + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0 + ]; + this._loadMatrix(matrix, false); + } + /** + * The matrix of the color matrix filter + * @member {number[]} + * @default [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0] + */ + get matrix() { + return this.resources.colorMatrixUniforms.uniforms.uColorMatrix; + } + set matrix(value) { + this.resources.colorMatrixUniforms.uniforms.uColorMatrix = value; + } + /** + * The opacity value to use when mixing the original and resultant colors. + * + * When the value is 0, the original color is used without modification. + * When the value is 1, the result color is used. + * When in the range (0, 1) the color is interpolated between the original and result by this amount. + * @default 1 + */ + get alpha() { + return this.resources.colorMatrixUniforms.uniforms.uAlpha; + } + set alpha(value) { + this.resources.colorMatrixUniforms.uniforms.uAlpha = value; + } + } + + var fragment$2 = "\nin vec2 vTextureCoord;\nin vec2 vFilterUv;\n\nout vec4 finalColor;\n\nuniform sampler2D uTexture;\nuniform sampler2D uMapTexture;\n\nuniform vec4 uInputClamp;\nuniform highp vec4 uInputSize;\nuniform mat2 uRotation;\nuniform vec2 uScale;\n\nvoid main()\n{\n vec4 map = texture(uMapTexture, vFilterUv);\n \n vec2 offset = uInputSize.zw * (uRotation * (map.xy - 0.5)) * uScale; \n\n finalColor = texture(uTexture, clamp(vTextureCoord + offset, uInputClamp.xy, uInputClamp.zw));\n}\n"; + + var vertex$1 = "in vec2 aPosition;\nout vec2 vTextureCoord;\nout vec2 vFilterUv;\n\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nuniform mat3 uFilterMatrix;\n\nvec4 filterVertexPosition( void )\n{\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n \n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( void )\n{\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvec2 getFilterCoord( void )\n{\n return ( uFilterMatrix * vec3( filterTextureCoord(), 1.0) ).xy;\n}\n\n\nvoid main(void)\n{\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n vFilterUv = getFilterCoord();\n}\n"; + + var source$2 = "\nstruct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct DisplacementUniforms {\n uFilterMatrix:mat3x3,\n uScale:vec2,\n uRotation:mat2x2\n};\n\n\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var filterUniforms : DisplacementUniforms;\n@group(1) @binding(1) var uMapTexture: texture_2d;\n@group(1) @binding(2) var uMapSampler : sampler;\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2,\n @location(1) filterUv : vec2,\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getFilterCoord(aPosition:vec2 ) -> vec2\n{\n return ( filterUniforms.uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;\n}\n\nfn getSize() -> vec2\n{\n\n \n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition),\n getFilterCoord(aPosition)\n );\n}\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2,\n @location(1) filterUv: vec2,\n @builtin(position) position: vec4\n) -> @location(0) vec4 {\n\n var map = textureSample(uMapTexture, uMapSampler, filterUv);\n\n var offset = gfu.uInputSize.zw * (filterUniforms.uRotation * (map.xy - 0.5)) * filterUniforms.uScale; \n \n return textureSample(uTexture, uSampler, clamp(uv + offset, gfu.uInputClamp.xy, gfu.uInputClamp.zw));\n}"; + + "use strict"; + var __defProp$p = Object.defineProperty; + var __defProps$b = Object.defineProperties; + var __getOwnPropDescs$b = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$p = Object.getOwnPropertySymbols; + var __hasOwnProp$p = Object.prototype.hasOwnProperty; + var __propIsEnum$p = Object.prototype.propertyIsEnumerable; + var __defNormalProp$p = (obj, key, value) => key in obj ? __defProp$p(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$p = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$p.call(b, prop)) + __defNormalProp$p(a, prop, b[prop]); + if (__getOwnPropSymbols$p) + for (var prop of __getOwnPropSymbols$p(b)) { + if (__propIsEnum$p.call(b, prop)) + __defNormalProp$p(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$b = (a, b) => __defProps$b(a, __getOwnPropDescs$b(b)); + var __objRest$a = (source2, exclude) => { + var target = {}; + for (var prop in source2) + if (__hasOwnProp$p.call(source2, prop) && exclude.indexOf(prop) < 0) + target[prop] = source2[prop]; + if (source2 != null && __getOwnPropSymbols$p) + for (var prop of __getOwnPropSymbols$p(source2)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$p.call(source2, prop)) + target[prop] = source2[prop]; + } + return target; + }; + class DisplacementFilter extends Filter { + constructor(...args) { + let options = args[0]; + if (options instanceof Sprite) { + if (args[1]) { + deprecation(v8_0_0, "DisplacementFilter now uses options object instead of params. {sprite, scale}"); + } + options = { sprite: options, scale: args[1] }; + } + const _a = options, { sprite, scale: scaleOption } = _a, rest = __objRest$a(_a, ["sprite", "scale"]); + let scale = scaleOption != null ? scaleOption : 20; + if (typeof scale === "number") { + scale = new Point(scale, scale); + } + const filterUniforms = new UniformGroup({ + uFilterMatrix: { value: new Matrix(), type: "mat3x3" }, + uScale: { value: scale, type: "vec2" }, + uRotation: { value: new Float32Array([0, 0, 0, 0]), type: "mat2x2" } + }); + const glProgram = GlProgram.from({ + vertex: vertex$1, + fragment: fragment$2, + name: "displacement-filter" + }); + const gpuProgram = GpuProgram.from({ + vertex: { + source: source$2, + entryPoint: "mainVertex" + }, + fragment: { + source: source$2, + entryPoint: "mainFragment" + } + }); + const textureSource = sprite.texture.source; + super(__spreadProps$b(__spreadValues$p({}, rest), { + gpuProgram, + glProgram, + resources: { + filterUniforms, + uMapTexture: textureSource, + uMapSampler: textureSource.style + } + })); + this._sprite = options.sprite; + this._sprite.renderable = false; + } + /** + * Applies the filter. + * @param filterManager - The manager. + * @param input - The input target. + * @param output - The output target. + * @param clearMode - clearMode. + */ + apply(filterManager, input, output, clearMode) { + const uniforms = this.resources.filterUniforms.uniforms; + filterManager.calculateSpriteMatrix( + uniforms.uFilterMatrix, + this._sprite + ); + const wt = this._sprite.worldTransform; + const lenX = Math.sqrt(wt.a * wt.a + wt.b * wt.b); + const lenY = Math.sqrt(wt.c * wt.c + wt.d * wt.d); + if (lenX !== 0 && lenY !== 0) { + uniforms.uRotation[0] = wt.a / lenX; + uniforms.uRotation[1] = wt.b / lenX; + uniforms.uRotation[2] = wt.c / lenY; + uniforms.uRotation[3] = wt.d / lenY; + } + this.resources.uMapTexture = this._sprite.texture.source; + filterManager.applyFilter(this, input, output, clearMode); + } + /** scaleX, scaleY for displacements */ + get scale() { + return this.resources.filterUniforms.uniforms.uScale; + } + } + + var fragment$1 = "\nin vec2 vTextureCoord;\nin vec4 vColor;\n\nout vec4 finalColor;\n\nuniform float uNoise;\nuniform float uSeed;\nuniform sampler2D uTexture;\n\nfloat rand(vec2 co)\n{\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main()\n{\n vec4 color = texture(uTexture, vTextureCoord);\n float randomValue = rand(gl_FragCoord.xy * uSeed);\n float diff = (randomValue - 0.5) * uNoise;\n\n // Un-premultiply alpha before applying the color matrix. See issue #3539.\n if (color.a > 0.0) {\n color.rgb /= color.a;\n }\n\n color.r += diff;\n color.g += diff;\n color.b += diff;\n\n // Premultiply alpha again.\n color.rgb *= color.a;\n\n finalColor = color;\n}\n"; + + var source$1 = "\n\nstruct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4,\n};\n\nstruct NoiseUniforms {\n uNoise:f32,\n uSeed:f32,\n};\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var noiseUniforms : NoiseUniforms;\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2\n{\n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition)\n );\n}\n\nfn rand(co:vec2) -> f32\n{\n return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2,\n @builtin(position) position: vec4\n) -> @location(0) vec4 {\n\n var pixelPosition = globalTextureCoord(position.xy);// / (getSize());//- gfu.uOutputFrame.xy);\n \n \n var sample = textureSample(uTexture, uSampler, uv);\n var randomValue = rand(pixelPosition.xy * noiseUniforms.uSeed);\n var diff = (randomValue - 0.5) * noiseUniforms.uNoise;\n \n // Un-premultiply alpha before applying the color matrix. See issue #3539.\n if (sample.a > 0.0) {\n sample.r /= sample.a;\n sample.g /= sample.a;\n sample.b /= sample.a;\n }\n\n sample.r += diff;\n sample.g += diff;\n sample.b += diff;\n\n // Premultiply alpha again.\n sample.r *= sample.a;\n sample.g *= sample.a;\n sample.b *= sample.a;\n \n return sample;\n}"; + + "use strict"; + var __defProp$o = Object.defineProperty; + var __defProps$a = Object.defineProperties; + var __getOwnPropDescs$a = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$o = Object.getOwnPropertySymbols; + var __hasOwnProp$o = Object.prototype.hasOwnProperty; + var __propIsEnum$o = Object.prototype.propertyIsEnumerable; + var __defNormalProp$o = (obj, key, value) => key in obj ? __defProp$o(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$o = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$o.call(b, prop)) + __defNormalProp$o(a, prop, b[prop]); + if (__getOwnPropSymbols$o) + for (var prop of __getOwnPropSymbols$o(b)) { + if (__propIsEnum$o.call(b, prop)) + __defNormalProp$o(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$a = (a, b) => __defProps$a(a, __getOwnPropDescs$a(b)); + var __objRest$9 = (source2, exclude) => { + var target = {}; + for (var prop in source2) + if (__hasOwnProp$o.call(source2, prop) && exclude.indexOf(prop) < 0) + target[prop] = source2[prop]; + if (source2 != null && __getOwnPropSymbols$o) + for (var prop of __getOwnPropSymbols$o(source2)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$o.call(source2, prop)) + target[prop] = source2[prop]; + } + return target; + }; + const _NoiseFilter = class _NoiseFilter extends Filter { + /** + * @param options - The options of the noise filter. + */ + constructor(options = {}) { + options = __spreadValues$o(__spreadValues$o({}, _NoiseFilter.defaultOptions), options); + const gpuProgram = GpuProgram.from({ + vertex: { + source: source$1, + entryPoint: "mainVertex" + }, + fragment: { + source: source$1, + entryPoint: "mainFragment" + } + }); + const glProgram = GlProgram.from({ + vertex: vertex$2, + fragment: fragment$1, + name: "noise-filter" + }); + const _a = options, { noise, seed } = _a, rest = __objRest$9(_a, ["noise", "seed"]); + super(__spreadProps$a(__spreadValues$o({}, rest), { + gpuProgram, + glProgram, + resources: { + noiseUniforms: new UniformGroup({ + uNoise: { value: 1, type: "f32" }, + uSeed: { value: 1, type: "f32" } + }) + } + })); + this.noise = noise; + this.seed = seed != null ? seed : Math.random(); + } + /** + * The amount of noise to apply, this value should be in the range (0, 1]. + * @default 0.5 + */ + get noise() { + return this.resources.noiseUniforms.uniforms.uNoise; + } + set noise(value) { + this.resources.noiseUniforms.uniforms.uNoise = value; + } + /** A seed value to apply to the random noise generation. `Math.random()` is a good value to use. */ + get seed() { + return this.resources.noiseUniforms.uniforms.uSeed; + } + set seed(value) { + this.resources.noiseUniforms.uniforms.uSeed = value; + } + }; + _NoiseFilter.defaultOptions = { + noise: 0.5 + }; + let NoiseFilter = _NoiseFilter; + + var fragment = "in vec2 vMaskCoord;\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform sampler2D uMaskTexture;\n\nuniform float uAlpha;\nuniform vec4 uMaskClamp;\n\nout vec4 finalColor;\n\nvoid main(void)\n{\n float clip = step(3.5,\n step(uMaskClamp.x, vMaskCoord.x) +\n step(uMaskClamp.y, vMaskCoord.y) +\n step(vMaskCoord.x, uMaskClamp.z) +\n step(vMaskCoord.y, uMaskClamp.w));\n\n // TODO look into why this is needed\n float npmAlpha = uAlpha; \n vec4 original = texture(uTexture, vTextureCoord);\n vec4 masky = texture(uMaskTexture, vMaskCoord);\n float alphaMul = 1.0 - npmAlpha * (1.0 - masky.a);\n\n original *= (alphaMul * masky.r * uAlpha * clip);\n\n finalColor = original;\n}\n"; + + var vertex = "in vec2 aPosition;\n\nout vec2 vTextureCoord;\nout vec2 vMaskCoord;\n\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\nuniform mat3 uFilterMatrix;\n\nvec4 filterVertexPosition( vec2 aPosition )\n{\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n \n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord( vec2 aPosition )\n{\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvec2 getFilterCoord( vec2 aPosition )\n{\n return ( uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;\n} \n\nvoid main(void)\n{\n gl_Position = filterVertexPosition(aPosition);\n vTextureCoord = filterTextureCoord(aPosition);\n vMaskCoord = getFilterCoord(aPosition);\n}\n"; + + var source = "struct GlobalFilterUniforms {\n uInputSize:vec4,\n uInputPixel:vec4,\n uInputClamp:vec4,\n uOutputFrame:vec4,\n uGlobalFrame:vec4,\n uOutputTexture:vec4, \n};\n\nstruct MaskUniforms {\n uFilterMatrix:mat3x3,\n uMaskClamp:vec4,\n uAlpha:f32,\n};\n\n\n@group(0) @binding(0) var gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var filterUniforms : MaskUniforms;\n@group(1) @binding(1) var uMaskTexture: texture_2d;\n\nstruct VSOutput {\n @builtin(position) position: vec4,\n @location(0) uv : vec2,\n @location(1) filterUv : vec2,\n };\n\nfn filterVertexPosition(aPosition:vec2) -> vec4\n{\n var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;\n\n position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;\n\n return vec4(position, 0.0, 1.0);\n}\n\nfn filterTextureCoord( aPosition:vec2 ) -> vec2\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2 ) -> vec2\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getFilterCoord(aPosition:vec2 ) -> vec2\n{\n return ( filterUniforms.uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;\n}\n\nfn getSize() -> vec2\n{\n\n \n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition),\n getFilterCoord(aPosition)\n );\n}\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2,\n @location(1) filterUv: vec2,\n @builtin(position) position: vec4\n) -> @location(0) vec4 {\n\n var maskClamp = filterUniforms.uMaskClamp;\n\n var clip = step(3.5,\n step(maskClamp.x, filterUv.x) +\n step(maskClamp.y, filterUv.y) +\n step(filterUv.x, maskClamp.z) +\n step(filterUv.y, maskClamp.w));\n\n var mask = textureSample(uMaskTexture, uSampler, filterUv);\n var source = textureSample(uTexture, uSampler, uv);\n \n var npmAlpha = 0.0;\n\n var alphaMul = 1.0 - npmAlpha * (1.0 - mask.a);\n\n var a = (alphaMul * mask.r) * clip;\n\n return vec4(source.rgb, source.a) * a;\n}"; + + "use strict"; + var __defProp$n = Object.defineProperty; + var __defProps$9 = Object.defineProperties; + var __getOwnPropDescs$9 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$n = Object.getOwnPropertySymbols; + var __hasOwnProp$n = Object.prototype.hasOwnProperty; + var __propIsEnum$n = Object.prototype.propertyIsEnumerable; + var __defNormalProp$n = (obj, key, value) => key in obj ? __defProp$n(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$n = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$n.call(b, prop)) + __defNormalProp$n(a, prop, b[prop]); + if (__getOwnPropSymbols$n) + for (var prop of __getOwnPropSymbols$n(b)) { + if (__propIsEnum$n.call(b, prop)) + __defNormalProp$n(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$9 = (a, b) => __defProps$9(a, __getOwnPropDescs$9(b)); + var __objRest$8 = (source2, exclude) => { + var target = {}; + for (var prop in source2) + if (__hasOwnProp$n.call(source2, prop) && exclude.indexOf(prop) < 0) + target[prop] = source2[prop]; + if (source2 != null && __getOwnPropSymbols$n) + for (var prop of __getOwnPropSymbols$n(source2)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$n.call(source2, prop)) + target[prop] = source2[prop]; + } + return target; + }; + class MaskFilter extends Filter { + constructor(options) { + const _a = options, { sprite } = _a, rest = __objRest$8(_a, ["sprite"]); + const textureMatrix = new TextureMatrix(sprite.texture); + const filterUniforms = new UniformGroup({ + uFilterMatrix: { value: new Matrix(), type: "mat3x3" }, + uMaskClamp: { value: textureMatrix.uClampFrame, type: "vec4" }, + uAlpha: { value: 1, type: "f32" } + }); + const gpuProgram = GpuProgram.from({ + vertex: { + source, + entryPoint: "mainVertex" + }, + fragment: { + source, + entryPoint: "mainFragment" + } + }); + const glProgram = GlProgram.from({ + vertex, + fragment, + name: "mask-filter" + }); + super(__spreadProps$9(__spreadValues$n({}, rest), { + gpuProgram, + glProgram, + resources: { + filterUniforms, + uMaskTexture: sprite.texture.source + } + })); + this.sprite = sprite; + this._textureMatrix = textureMatrix; + } + apply(filterManager, input, output, clearMode) { + this._textureMatrix.texture = this.sprite.texture; + filterManager.calculateSpriteMatrix( + this.resources.filterUniforms.uniforms.uFilterMatrix, + this.sprite + ).prepend(this._textureMatrix.mapCoord); + this.resources.uMaskTexture = this.sprite.texture.source; + filterManager.applyFilter(this, input, output, clearMode); + } + } + + var hsl = "fn getLuminosity(c: vec3) -> f32 {\n return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;\n}\n\nfn setLuminosity(c: vec3, lum: f32) -> vec3 {\n let d: f32 = lum - getLuminosity(c);\n let newColor: vec3 = c.rgb + vec3(d, d, d);\n\n // clip back into legal range\n let newLum: f32 = getLuminosity(newColor);\n let cMin: f32 = min(newColor.r, min(newColor.g, newColor.b));\n let cMax: f32 = max(newColor.r, max(newColor.g, newColor.b));\n\n let t1: f32 = newLum / (newLum - cMin);\n let t2: f32 = (1.0 - newLum) / (cMax - newLum);\n\n let finalColor = mix(vec3(newLum, newLum, newLum), newColor, select(select(1.0, t2, cMax > 1.0), t1, cMin < 0.0));\n\n return finalColor;\n}\n\nfn getSaturation(c: vec3) -> f32 {\n return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));\n}\n\n// Set saturation if color components are sorted in ascending order.\nfn setSaturationMinMidMax(cSorted: vec3, s: f32) -> vec3 {\n var result: vec3;\n if (cSorted.z > cSorted.x) {\n let newY = (((cSorted.y - cSorted.x) * s) / (cSorted.z - cSorted.x));\n result = vec3(0.0, newY, s);\n } else {\n result = vec3(0.0, 0.0, 0.0);\n }\n return vec3(result.x, result.y, result.z);\n}\n\nfn setSaturation(c: vec3, s: f32) -> vec3 {\n var result: vec3 = c;\n\n if (c.r <= c.g && c.r <= c.b) {\n if (c.g <= c.b) {\n result = setSaturationMinMidMax(result, s);\n } else {\n var temp: vec3 = vec3(result.r, result.b, result.g);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3(temp.r, temp.b, temp.g);\n }\n } else if (c.g <= c.r && c.g <= c.b) {\n if (c.r <= c.b) {\n var temp: vec3 = vec3(result.g, result.r, result.b);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3(temp.g, temp.r, temp.b);\n } else {\n var temp: vec3 = vec3(result.g, result.b, result.r);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3(temp.g, temp.b, temp.r);\n }\n } else {\n if (c.r <= c.g) {\n var temp: vec3 = vec3(result.b, result.r, result.g);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3(temp.b, temp.r, temp.g);\n } else {\n var temp: vec3 = vec3(result.b, result.g, result.r);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3(temp.b, temp.g, temp.r);\n }\n }\n\n return result;\n}"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + function pointInTriangle(px, py, x1, y1, x2, y2, x3, y3) { + const v2x = x3 - x1; + const v2y = y3 - y1; + const v1x = x2 - x1; + const v1y = y2 - y1; + const v0x = px - x1; + const v0y = py - y1; + const dot00 = v2x * v2x + v2y * v2y; + const dot01 = v2x * v1x + v2y * v1y; + const dot02 = v2x * v0x + v2y * v0y; + const dot11 = v1x * v1x + v1y * v1y; + const dot12 = v1x * v0x + v1y * v0y; + const invDenom = 1 / (dot00 * dot11 - dot01 * dot01); + const u = (dot11 * dot02 - dot01 * dot12) * invDenom; + const v = (dot00 * dot12 - dot01 * dot02) * invDenom; + return u >= 0 && v >= 0 && u + v < 1; + } + + "use strict"; + + "use strict"; + + "use strict"; + class Triangle { + /** + * @param x - The X coord of the first point. + * @param y - The Y coord of the first point. + * @param x2 - The X coord of the second point. + * @param y2 - The Y coord of the second point. + * @param x3 - The X coord of the third point. + * @param y3 - The Y coord of the third point. + */ + constructor(x = 0, y = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0) { + /** + * The type of the object, mainly used to avoid `instanceof` checks + * @default 'triangle' + */ + this.type = "triangle"; + this.x = x; + this.y = y; + this.x2 = x2; + this.y2 = y2; + this.x3 = x3; + this.y3 = y3; + } + /** + * Checks whether the x and y coordinates given are contained within this triangle + * @param x - The X coordinate of the point to test + * @param y - The Y coordinate of the point to test + * @returns Whether the x/y coordinates are within this Triangle + */ + contains(x, y) { + const s = (this.x - this.x3) * (y - this.y3) - (this.y - this.y3) * (x - this.x3); + const t = (this.x2 - this.x) * (y - this.y) - (this.y2 - this.y) * (x - this.x); + if (s < 0 !== t < 0 && s !== 0 && t !== 0) { + return false; + } + const d = (this.x3 - this.x2) * (y - this.y2) - (this.y3 - this.y2) * (x - this.x2); + return d === 0 || d < 0 === s + t <= 0; + } + /** + * Checks whether the x and y coordinates given are contained within this triangle including the stroke. + * @param pointX - The X coordinate of the point to test + * @param pointY - The Y coordinate of the point to test + * @param strokeWidth - The width of the line to check + * @returns Whether the x/y coordinates are within this triangle + */ + strokeContains(pointX, pointY, strokeWidth) { + const halfStrokeWidth = strokeWidth / 2; + const halfStrokeWidthSquared = halfStrokeWidth * halfStrokeWidth; + const { x, x2, x3, y, y2, y3 } = this; + if (squaredDistanceToLineSegment(pointX, pointY, x, y, x2, y3) <= halfStrokeWidthSquared || squaredDistanceToLineSegment(pointX, pointY, x2, y2, x3, y3) <= halfStrokeWidthSquared || squaredDistanceToLineSegment(pointX, pointY, x3, y3, x, y) <= halfStrokeWidthSquared) { + return true; + } + return false; + } + /** + * Creates a clone of this Triangle + * @returns a copy of the triangle + */ + clone() { + const triangle = new Triangle( + this.x, + this.y, + this.x2, + this.y2, + this.x3, + this.y3 + ); + return triangle; + } + /** + * Copies another triangle to this one. + * @param triangle - The triangle to copy from. + * @returns Returns itself. + */ + copyFrom(triangle) { + this.x = triangle.x; + this.y = triangle.y; + this.x2 = triangle.x2; + this.y2 = triangle.y2; + this.x3 = triangle.x3; + this.y3 = triangle.y3; + return this; + } + /** + * Copies this triangle to another one. + * @param triangle - The triangle to copy to. + * @returns Returns given parameter. + */ + copyTo(triangle) { + triangle.copyFrom(this); + return triangle; + } + /** + * Returns the framing rectangle of the triangle as a Rectangle object + * @param out - optional rectangle to store the result + * @returns The framing rectangle + */ + getBounds(out) { + out = out || new Rectangle(); + const minX = Math.min(this.x, this.x2, this.x3); + const maxX = Math.max(this.x, this.x2, this.x3); + const minY = Math.min(this.y, this.y2, this.y3); + const maxY = Math.max(this.y, this.y2, this.y3); + out.x = minX; + out.y = minY; + out.width = maxX - minX; + out.height = maxY - minY; + return out; + } + } + + "use strict"; + + "use strict"; + const _PrepareBase = class _PrepareBase { + /** + * * @param {Renderer} renderer - A reference to the current renderer + * @param renderer + */ + constructor(renderer) { + /** called per frame by the ticker, defer processing to next tick */ + this._tick = () => { + this.timeout = setTimeout(this._processQueue, 0); + }; + /** process the queue up to max item limit per frame */ + this._processQueue = () => { + const { queue } = this; + let itemsProcessed = 0; + while (queue.length && itemsProcessed < _PrepareBase.uploadsPerFrame) { + const queueItem = queue.shift(); + this.uploadQueueItem(queueItem); + itemsProcessed++; + } + if (queue.length) { + Ticker.system.addOnce(this._tick, this, UPDATE_PRIORITY.UTILITY); + } else { + this._resolve(); + } + }; + this.renderer = renderer; + this.queue = []; + this.resolves = []; + } + /** + * Return a copy of the queue + * @returns {PrepareQueueItem[]} The queue + */ + getQueue() { + return [...this.queue]; + } + /** + * Add a textures or graphics resource to the queue + * @param {PrepareSourceItem | PrepareSourceItem[]} resource + */ + add(resource) { + const resourceArray = Array.isArray(resource) ? resource : [resource]; + for (const resourceItem of resourceArray) { + if (resourceItem instanceof Container) { + this._addContainer(resourceItem); + } else { + this.resolveQueueItem(resourceItem, this.queue); + } + } + return this; + } + /** + * Recursively add a container and its children to the queue + * @param {Container} container - The container to add to the queue + */ + _addContainer(container) { + this.resolveQueueItem(container, this.queue); + for (const child of container.children) { + this._addContainer(child); + } + } + /** + * Upload all the textures and graphics to the GPU (optionally add more resources to the queue first) + * @param {PrepareSourceItem | PrepareSourceItem[] | undefined} resource + */ + upload(resource) { + if (resource) { + this.add(resource); + } + return new Promise((resolve) => { + if (this.queue.length) { + this.resolves.push(resolve); + this.dedupeQueue(); + Ticker.system.addOnce(this._tick, this, UPDATE_PRIORITY.UTILITY); + } else { + resolve(); + } + }); + } + /** eliminate duplicates before processing */ + dedupeQueue() { + const hash = /* @__PURE__ */ Object.create(null); + let nextUnique = 0; + for (let i = 0; i < this.queue.length; i++) { + const current = this.queue[i]; + if (!hash[current.uid]) { + hash[current.uid] = true; + this.queue[nextUnique++] = current; + } + } + this.queue.length = nextUnique; + } + /** Call all the resolve callbacks */ + _resolve() { + const { resolves } = this; + const array = resolves.slice(0); + resolves.length = 0; + for (const resolve of array) { + resolve(); + } + } + }; + /** The number of uploads to process per frame */ + _PrepareBase.uploadsPerFrame = 4; + let PrepareBase = _PrepareBase; + + "use strict"; + var __defProp$m = Object.defineProperty; + var __getOwnPropSymbols$m = Object.getOwnPropertySymbols; + var __hasOwnProp$m = Object.prototype.hasOwnProperty; + var __propIsEnum$m = Object.prototype.propertyIsEnumerable; + var __defNormalProp$m = (obj, key, value) => key in obj ? __defProp$m(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$m = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$m.call(b, prop)) + __defNormalProp$m(a, prop, b[prop]); + if (__getOwnPropSymbols$m) + for (var prop of __getOwnPropSymbols$m(b)) { + if (__propIsEnum$m.call(b, prop)) + __defNormalProp$m(a, prop, b[prop]); + } + return a; + }; + var __objRest$7 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$m.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$m) + for (var prop of __getOwnPropSymbols$m(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$m.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class Mesh extends Container { + constructor(...args) { + var _b; + let options = args[0]; + if (options instanceof Geometry) { + deprecation(v8_0_0, "Mesh: use new Mesh({ geometry, shader }) instead"); + options = { + geometry: options, + shader: args[1] + }; + if (args[3]) { + deprecation(v8_0_0, "Mesh: drawMode argument has been removed, use geometry.topology instead"); + options.geometry.topology = args[3]; + } + } + const _a = options, { geometry, shader, texture, roundPixels, state } = _a, rest = __objRest$7(_a, ["geometry", "shader", "texture", "roundPixels", "state"]); + super(__spreadValues$m({ + label: "Mesh" + }, rest)); + this.renderPipeId = "mesh"; + this.canBundle = true; + this._roundPixels = 0; + this.allowChildren = false; + this.shader = shader; + this.texture = (_b = texture != null ? texture : shader == null ? void 0 : shader.texture) != null ? _b : Texture.WHITE; + this.state = state != null ? state : State.for2d(); + this._geometry = geometry; + this._geometry.on("update", this.onViewUpdate, this); + this.roundPixels = roundPixels != null ? roundPixels : false; + } + /** + * Whether or not to round the x/y position of the mesh. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + /** Alias for {@link scene.Mesh#shader}. */ + get material() { + deprecation(v8_0_0, "mesh.material property has been removed, use mesh.shader instead"); + return this._shader; + } + /** + * Represents the vertex and fragment shaders that processes the geometry and runs on the GPU. + * Can be shared between multiple Mesh objects. + */ + set shader(value) { + if (this._shader === value) + return; + this._shader = value; + this.onViewUpdate(); + } + get shader() { + return this._shader; + } + /** + * Includes vertex positions, face indices, colors, UVs, and + * custom attributes within buffers, reducing the cost of passing all + * this data to the GPU. Can be shared between multiple Mesh objects. + */ + set geometry(value) { + var _a; + if (this._geometry === value) + return; + (_a = this._geometry) == null ? void 0 : _a.off("update", this.onViewUpdate, this); + value.on("update", this.onViewUpdate, this); + this._geometry = value; + this.onViewUpdate(); + } + get geometry() { + return this._geometry; + } + /** The texture that the Mesh uses. Null for non-MeshMaterial shaders */ + set texture(value) { + value || (value = Texture.EMPTY); + const currentTexture = this._texture; + if (currentTexture === value) + return; + if (currentTexture && currentTexture.dynamic) + currentTexture.off("update", this.onViewUpdate, this); + if (value.dynamic) + value.on("update", this.onViewUpdate, this); + if (this.shader) { + this.shader.texture = value; + } + this._texture = value; + this.onViewUpdate(); + } + get texture() { + return this._texture; + } + get batched() { + if (this._shader) + return false; + if (this._geometry instanceof MeshGeometry) { + if (this._geometry.batchMode === "auto") { + return this._geometry.positions.length / 2 <= 100; + } + return this._geometry.batchMode === "batch"; + } + return false; + } + /** + * The local bounds of the mesh. + * @type {rendering.Bounds} + */ + get bounds() { + return this._geometry.bounds; + } + /** + * Adds the bounds of this object to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + bounds.addBounds(this.geometry.bounds); + } + /** + * Checks if the object contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + const { x, y } = point; + if (!this.bounds.containsPoint(x, y)) + return false; + const vertices = this.geometry.getBuffer("aPosition").data; + const step = this.geometry.topology === "triangle-strip" ? 3 : 1; + if (this.geometry.getIndex()) { + const indices = this.geometry.getIndex().data; + const len = indices.length; + for (let i = 0; i + 2 < len; i += step) { + const ind0 = indices[i] * 2; + const ind1 = indices[i + 1] * 2; + const ind2 = indices[i + 2] * 2; + if (pointInTriangle( + x, + y, + vertices[ind0], + vertices[ind0 + 1], + vertices[ind1], + vertices[ind1 + 1], + vertices[ind2], + vertices[ind2 + 1] + )) { + return true; + } + } + } else { + const len = vertices.length / 2; + for (let i = 0; i + 2 < len; i += step) { + const ind0 = i * 2; + const ind1 = (i + 1) * 2; + const ind2 = (i + 2) * 2; + if (pointInTriangle( + x, + y, + vertices[ind0], + vertices[ind0 + 1], + vertices[ind1], + vertices[ind1 + 1], + vertices[ind2], + vertices[ind2 + 1] + )) { + return true; + } + } + } + return false; + } + /** @ignore */ + onViewUpdate() { + this._didChangeId += 1 << 12; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + /** + * Destroys this sprite renderable and optionally its texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well + */ + destroy(options) { + var _a; + super.destroy(options); + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + this._texture.destroy(destroyTextureSource); + } + (_a = this._geometry) == null ? void 0 : _a.off("update", this.onViewUpdate, this); + this._texture = null; + this._geometry = null; + this._shader = null; + } + } + + "use strict"; + class AnimatedSprite extends Sprite { + /** + * @param textures - An array of {@link Texture} or frame + * objects that make up the animation. + * @param {boolean} [autoUpdate=true] - Whether to use Ticker.shared to auto update animation time. + */ + constructor(textures, autoUpdate = true) { + super(textures[0] instanceof Texture ? textures[0] : textures[0].texture); + this._textures = null; + this._durations = null; + this._autoUpdate = autoUpdate; + this._isConnectedToTicker = false; + this.animationSpeed = 1; + this.loop = true; + this.updateAnchor = false; + this.onComplete = null; + this.onFrameChange = null; + this.onLoop = null; + this._currentTime = 0; + this._playing = false; + this._previousFrame = null; + this.textures = textures; + } + /** Stops the AnimatedSprite. */ + stop() { + if (!this._playing) { + return; + } + this._playing = false; + if (this._autoUpdate && this._isConnectedToTicker) { + Ticker.shared.remove(this.update, this); + this._isConnectedToTicker = false; + } + } + /** Plays the AnimatedSprite. */ + play() { + if (this._playing) { + return; + } + this._playing = true; + if (this._autoUpdate && !this._isConnectedToTicker) { + Ticker.shared.add(this.update, this, UPDATE_PRIORITY.HIGH); + this._isConnectedToTicker = true; + } + } + /** + * Stops the AnimatedSprite and goes to a specific frame. + * @param frameNumber - Frame index to stop at. + */ + gotoAndStop(frameNumber) { + this.stop(); + this.currentFrame = frameNumber; + } + /** + * Goes to a specific frame and begins playing the AnimatedSprite. + * @param frameNumber - Frame index to start at. + */ + gotoAndPlay(frameNumber) { + this.currentFrame = frameNumber; + this.play(); + } + /** + * Updates the object transform for rendering. + * @param ticker - the ticker to use to update the object. + */ + update(ticker) { + if (!this._playing) { + return; + } + const deltaTime = ticker.deltaTime; + const elapsed = this.animationSpeed * deltaTime; + const previousFrame = this.currentFrame; + if (this._durations !== null) { + let lag = this._currentTime % 1 * this._durations[this.currentFrame]; + lag += elapsed / 60 * 1e3; + while (lag < 0) { + this._currentTime--; + lag += this._durations[this.currentFrame]; + } + const sign = Math.sign(this.animationSpeed * deltaTime); + this._currentTime = Math.floor(this._currentTime); + while (lag >= this._durations[this.currentFrame]) { + lag -= this._durations[this.currentFrame] * sign; + this._currentTime += sign; + } + this._currentTime += lag / this._durations[this.currentFrame]; + } else { + this._currentTime += elapsed; + } + if (this._currentTime < 0 && !this.loop) { + this.gotoAndStop(0); + if (this.onComplete) { + this.onComplete(); + } + } else if (this._currentTime >= this._textures.length && !this.loop) { + this.gotoAndStop(this._textures.length - 1); + if (this.onComplete) { + this.onComplete(); + } + } else if (previousFrame !== this.currentFrame) { + if (this.loop && this.onLoop) { + if (this.animationSpeed > 0 && this.currentFrame < previousFrame || this.animationSpeed < 0 && this.currentFrame > previousFrame) { + this.onLoop(); + } + } + this._updateTexture(); + } + } + /** Updates the displayed texture to match the current frame index. */ + _updateTexture() { + const currentFrame = this.currentFrame; + if (this._previousFrame === currentFrame) { + return; + } + this._previousFrame = currentFrame; + this.texture = this._textures[currentFrame]; + if (this.updateAnchor) { + this.anchor.copyFrom(this.texture.defaultAnchor); + } + if (this.onFrameChange) { + this.onFrameChange(this.currentFrame); + } + } + /** Stops the AnimatedSprite and destroys it. */ + destroy() { + this.stop(); + super.destroy(); + this.onComplete = null; + this.onFrameChange = null; + this.onLoop = null; + } + /** + * A short hand way of creating an AnimatedSprite from an array of frame ids. + * @param frames - The array of frames ids the AnimatedSprite will use as its texture frames. + * @returns - The new animated sprite with the specified frames. + */ + static fromFrames(frames) { + const textures = []; + for (let i = 0; i < frames.length; ++i) { + textures.push(Texture.from(frames[i])); + } + return new AnimatedSprite(textures); + } + /** + * A short hand way of creating an AnimatedSprite from an array of image ids. + * @param images - The array of image urls the AnimatedSprite will use as its texture frames. + * @returns The new animate sprite with the specified images as frames. + */ + static fromImages(images) { + const textures = []; + for (let i = 0; i < images.length; ++i) { + textures.push(Texture.from(images[i])); + } + return new AnimatedSprite(textures); + } + /** + * The total number of frames in the AnimatedSprite. This is the same as number of textures + * assigned to the AnimatedSprite. + * @readonly + * @default 0 + */ + get totalFrames() { + return this._textures.length; + } + /** The array of textures used for this AnimatedSprite. */ + get textures() { + return this._textures; + } + set textures(value) { + if (value[0] instanceof Texture) { + this._textures = value; + this._durations = null; + } else { + this._textures = []; + this._durations = []; + for (let i = 0; i < value.length; i++) { + this._textures.push(value[i].texture); + this._durations.push(value[i].time); + } + } + this._previousFrame = null; + this.gotoAndStop(0); + this._updateTexture(); + } + /** The AnimatedSprite's current frame index. */ + get currentFrame() { + let currentFrame = Math.floor(this._currentTime) % this._textures.length; + if (currentFrame < 0) { + currentFrame += this._textures.length; + } + return currentFrame; + } + set currentFrame(value) { + if (value < 0 || value > this.totalFrames - 1) { + throw new Error(`[AnimatedSprite]: Invalid frame index value ${value}, expected to be between 0 and totalFrames ${this.totalFrames}.`); + } + const previousFrame = this.currentFrame; + this._currentTime = value; + if (previousFrame !== this.currentFrame) { + this._updateTexture(); + } + } + /** + * Indicates if the AnimatedSprite is currently playing. + * @readonly + */ + get playing() { + return this._playing; + } + /** Whether to use Ticker.shared to auto update animation time. */ + get autoUpdate() { + return this._autoUpdate; + } + set autoUpdate(value) { + if (value !== this._autoUpdate) { + this._autoUpdate = value; + if (!this._autoUpdate && this._isConnectedToTicker) { + Ticker.shared.remove(this.update, this); + this._isConnectedToTicker = false; + } else if (this._autoUpdate && !this._isConnectedToTicker && this._playing) { + Ticker.shared.add(this.update, this); + this._isConnectedToTicker = true; + } + } + } + } + + "use strict"; + class Transform { + /** + * @param options - Options for the transform. + * @param options.matrix - The matrix to use. + * @param options.observer - The observer to use. + */ + constructor({ matrix, observer } = {}) { + this.dirty = true; + this._matrix = matrix != null ? matrix : new Matrix(); + this.observer = observer; + this.position = new ObservablePoint(this, 0, 0); + this.scale = new ObservablePoint(this, 1, 1); + this.pivot = new ObservablePoint(this, 0, 0); + this.skew = new ObservablePoint(this, 0, 0); + this._rotation = 0; + this._cx = 1; + this._sx = 0; + this._cy = 0; + this._sy = 1; + } + /** + * This matrix is computed by combining this Transforms position, scale, rotation, skew, and pivot + * properties into a single matrix. + * @readonly + */ + get matrix() { + const lt = this._matrix; + if (!this.dirty) + return lt; + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + lt.tx = this.position.x - (this.pivot.x * lt.a + this.pivot.y * lt.c); + lt.ty = this.position.y - (this.pivot.x * lt.b + this.pivot.y * lt.d); + this.dirty = false; + return lt; + } + /** + * Called when a value changes. + * @param point + * @internal + * @private + */ + _onUpdate(point) { + var _a; + this.dirty = true; + if (point === this.skew) { + this.updateSkew(); + } + (_a = this.observer) == null ? void 0 : _a._onUpdate(this); + } + /** Called when the skew or the rotation changes. */ + updateSkew() { + this._cx = Math.cos(this._rotation + this.skew.y); + this._sx = Math.sin(this._rotation + this.skew.y); + this._cy = -Math.sin(this._rotation - this.skew.x); + this._sy = Math.cos(this._rotation - this.skew.x); + this.dirty = true; + } + toString() { + return `[pixi.js/math:Transform position=(${this.position.x}, ${this.position.y}) rotation=${this.rotation} scale=(${this.scale.x}, ${this.scale.y}) skew=(${this.skew.x}, ${this.skew.y}) ]`; + } + /** + * Decomposes a matrix and sets the transforms properties based on it. + * @param matrix - The matrix to decompose + */ + setFromMatrix(matrix) { + matrix.decompose(this); + this.dirty = true; + } + /** The rotation of the object in radians. */ + get rotation() { + return this._rotation; + } + set rotation(value) { + if (this._rotation !== value) { + this._rotation = value; + this._onUpdate(this.skew); + } + } + } + + "use strict"; + var __defProp$l = Object.defineProperty; + var __getOwnPropSymbols$l = Object.getOwnPropertySymbols; + var __hasOwnProp$l = Object.prototype.hasOwnProperty; + var __propIsEnum$l = Object.prototype.propertyIsEnumerable; + var __defNormalProp$l = (obj, key, value) => key in obj ? __defProp$l(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$l = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$l.call(b, prop)) + __defNormalProp$l(a, prop, b[prop]); + if (__getOwnPropSymbols$l) + for (var prop of __getOwnPropSymbols$l(b)) { + if (__propIsEnum$l.call(b, prop)) + __defNormalProp$l(a, prop, b[prop]); + } + return a; + }; + var __objRest$6 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$l.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$l) + for (var prop of __getOwnPropSymbols$l(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$l.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + const _TilingSprite = class _TilingSprite extends Container { + constructor(...args) { + let options = args[0] || {}; + if (options instanceof Texture) { + options = { texture: options }; + } + if (args.length > 1) { + deprecation(v8_0_0, "use new TilingSprite({ texture, width:100, height:100 }) instead"); + options.width = args[1]; + options.height = args[2]; + } + options = __spreadValues$l(__spreadValues$l({}, _TilingSprite.defaultOptions), options); + const _a = options != null ? options : {}, { + texture, + anchor, + tilePosition, + tileScale, + tileRotation, + width, + height, + applyAnchorToTexture, + roundPixels + } = _a, rest = __objRest$6(_a, [ + "texture", + "anchor", + "tilePosition", + "tileScale", + "tileRotation", + "width", + "height", + "applyAnchorToTexture", + "roundPixels" + ]); + super(__spreadValues$l({ + label: "TilingSprite" + }, rest)); + this.renderPipeId = "tilingSprite"; + this.canBundle = true; + this.batched = true; + this._roundPixels = 0; + this._bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 }; + this._boundsDirty = true; + this.allowChildren = false; + this._anchor = new ObservablePoint( + { + _onUpdate: () => { + this.onViewUpdate(); + } + } + ); + this._applyAnchorToTexture = applyAnchorToTexture; + this.texture = texture; + this._width = width != null ? width : texture.width; + this._height = height != null ? height : texture.height; + this._tileTransform = new Transform({ + observer: { + _onUpdate: () => this.onViewUpdate() + } + }); + if (anchor) + this.anchor = anchor; + this.tilePosition = tilePosition; + this.tileScale = tileScale; + this.tileRotation = tileRotation; + this.roundPixels = roundPixels != null ? roundPixels : false; + } + /** + * Creates a new tiling sprite. + * @param source - The source to create the texture from. + * @param options - The options for creating the tiling sprite. + * @returns A new tiling sprite. + */ + static from(source, options = {}) { + if (typeof source === "string") { + return new _TilingSprite(__spreadValues$l({ + texture: Cache.get(source) + }, options)); + } + return new _TilingSprite(__spreadValues$l({ + texture: source + }, options)); + } + /** + * Changes frame clamping in corresponding textureMatrix + * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas + * @default 0.5 + * @member {number} + */ + get clampMargin() { + return this._texture.textureMatrix.clampMargin; + } + set clampMargin(value) { + this._texture.textureMatrix.clampMargin = value; + } + /** + * The anchor sets the origin point of the sprite. The default value is taken from the {@link Texture} + * and passed to the constructor. + * + * The default is `(0,0)`, this means the sprite's origin is the top left. + * + * Setting the anchor to `(0.5,0.5)` means the sprite's origin is centered. + * + * Setting the anchor to `(1,1)` would mean the sprite's origin point will be the bottom right corner. + * + * If you pass only single parameter, it will set both x and y to the same value as shown in the example below. + * @example + * import { TilingSprite } from 'pixi.js'; + * + * const sprite = new TilingSprite({texture: Texture.WHITE}); + * sprite.anchor.set(0.5); // This will set the origin to center. (0.5) is same as (0.5, 0.5). + */ + get anchor() { + return this._anchor; + } + set anchor(value) { + typeof value === "number" ? this._anchor.set(value) : this._anchor.copyFrom(value); + } + /** The offset of the image that is being tiled. */ + get tilePosition() { + return this._tileTransform.position; + } + set tilePosition(value) { + this._tileTransform.position.copyFrom(value); + } + /** The scaling of the image that is being tiled. */ + get tileScale() { + return this._tileTransform.scale; + } + set tileScale(value) { + typeof value === "number" ? this._tileTransform.scale.set(value) : this._tileTransform.scale.copyFrom(value); + } + set tileRotation(value) { + this._tileTransform.rotation = value; + } + /** The rotation of the image that is being tiled. */ + get tileRotation() { + return this._tileTransform.rotation; + } + /** The transform of the image that is being tiled. */ + get tileTransform() { + return this._tileTransform; + } + /** + * Whether or not to round the x/y position of the sprite. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + /** + * The local bounds of the sprite. + * @type {rendering.Bounds} + */ + get bounds() { + if (this._boundsDirty) { + this._updateBounds(); + this._boundsDirty = false; + } + return this._bounds; + } + set texture(value) { + value || (value = Texture.EMPTY); + const currentTexture = this._texture; + if (currentTexture === value) + return; + if (currentTexture && currentTexture.dynamic) + currentTexture.off("update", this.onViewUpdate, this); + if (value.dynamic) + value.on("update", this.onViewUpdate, this); + this._texture = value; + this.onViewUpdate(); + } + /** The texture that the sprite is using. */ + get texture() { + return this._texture; + } + /** The width of the tiling area. */ + set width(value) { + this._width = value; + this.onViewUpdate(); + } + get width() { + return this._width; + } + set height(value) { + this._height = value; + this.onViewUpdate(); + } + /** The height of the tiling area. */ + get height() { + return this._height; + } + _updateBounds() { + const bounds = this._bounds; + const anchor = this._anchor; + const width = this._width; + const height = this._height; + bounds.maxX = -anchor._x * width; + bounds.minX = bounds.maxX + width; + bounds.maxY = -anchor._y * height; + bounds.minY = bounds.maxY + height; + } + /** + * Adds the bounds of this object to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + const _bounds = this.bounds; + bounds.addFrame( + _bounds.minX, + _bounds.minY, + _bounds.maxX, + _bounds.maxY + ); + } + /** + * Checks if the object contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + const width = this._width; + const height = this._height; + const x1 = -width * this._anchor._x; + let y1 = 0; + if (point.x >= x1 && point.x <= x1 + width) { + y1 = -height * this._anchor._y; + if (point.y >= y1 && point.y <= y1 + height) + return true; + } + return false; + } + onViewUpdate() { + this._boundsDirty = true; + this._didTilingSpriteUpdate = true; + this._didChangeId += 1 << 12; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + /** + * Destroys this sprite renderable and optionally its texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well + */ + destroy(options = false) { + super.destroy(options); + this._anchor = null; + this._tileTransform = null; + this._bounds = null; + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + this._texture.destroy(destroyTextureSource); + } + this._texture = null; + } + }; + /** default options for the TilingSprite */ + _TilingSprite.defaultOptions = { + /** The texture to use for the sprite. */ + texture: Texture.EMPTY, + /** The anchor point of the sprite */ + anchor: { x: 0, y: 0 }, + /** The offset of the image that is being tiled. */ + tilePosition: { x: 0, y: 0 }, + /** Scaling of the image that is being tiled. */ + tileScale: { x: 1, y: 1 }, + /** The rotation of the image that is being tiled. */ + tileRotation: 0, + /** TODO */ + applyAnchorToTexture: false + }; + let TilingSprite = _TilingSprite; + + "use strict"; + var __defProp$k = Object.defineProperty; + var __getOwnPropSymbols$k = Object.getOwnPropertySymbols; + var __hasOwnProp$k = Object.prototype.hasOwnProperty; + var __propIsEnum$k = Object.prototype.propertyIsEnumerable; + var __defNormalProp$k = (obj, key, value) => key in obj ? __defProp$k(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$k = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$k.call(b, prop)) + __defNormalProp$k(a, prop, b[prop]); + if (__getOwnPropSymbols$k) + for (var prop of __getOwnPropSymbols$k(b)) { + if (__propIsEnum$k.call(b, prop)) + __defNormalProp$k(a, prop, b[prop]); + } + return a; + }; + var __objRest$5 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$k.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$k) + for (var prop of __getOwnPropSymbols$k(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$k.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class AbstractText extends Container { + constructor(options, styleClass) { + const _a = options, { text, resolution, style, anchor, width, height, roundPixels } = _a, rest = __objRest$5(_a, ["text", "resolution", "style", "anchor", "width", "height", "roundPixels"]); + super(__spreadValues$k({}, rest)); + this.batched = true; + this._resolution = null; + this._didTextUpdate = true; + this._roundPixels = 0; + this._bounds = new Bounds(); + this._boundsDirty = true; + this._styleClass = styleClass; + this.text = text != null ? text : ""; + this.style = style; + this.resolution = resolution != null ? resolution : null; + this.allowChildren = false; + this._anchor = new ObservablePoint( + { + _onUpdate: () => { + this.onViewUpdate(); + } + } + ); + if (anchor) + this.anchor = anchor; + this.roundPixels = roundPixels != null ? roundPixels : false; + if (width) + this.width = width; + if (height) + this.height = height; + } + /** + * The anchor sets the origin point of the text. + * The default is `(0,0)`, this means the text's origin is the top left. + * + * Setting the anchor to `(0.5,0.5)` means the text's origin is centered. + * + * Setting the anchor to `(1,1)` would mean the text's origin point will be the bottom right corner. + * + * If you pass only single parameter, it will set both x and y to the same value as shown in the example below. + * @example + * import { Text } from 'pixi.js'; + * + * const text = new Text('hello world'); + * text.anchor.set(0.5); // This will set the origin to center. (0.5) is same as (0.5, 0.5). + */ + get anchor() { + return this._anchor; + } + set anchor(value) { + typeof value === "number" ? this._anchor.set(value) : this._anchor.copyFrom(value); + } + /** + * Whether or not to round the x/y position of the text. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + /** Set the copy for the text object. To split a line you can use '\n'. */ + set text(value) { + value = value.toString(); + if (this._text === value) + return; + this._text = value; + this.onViewUpdate(); + } + get text() { + return this._text; + } + /** + * The resolution / device pixel ratio of the canvas. + * @default 1 + */ + set resolution(value) { + this._resolution = value; + this.onViewUpdate(); + } + get resolution() { + return this._resolution; + } + get style() { + return this._style; + } + /** + * Set the style of the text. + * + * Set up an event listener to listen for changes on the style object and mark the text as dirty. + * + * If setting the `style` can also be partial {@link AnyTextStyleOptions}. + * @type { + * text.TextStyle | + * Partial | + * text.TextStyleOptions | + * text.HTMLTextStyle | + * Partial | + * text.HTMLTextStyleOptions + * } + */ + set style(style) { + var _a; + style = style || {}; + (_a = this._style) == null ? void 0 : _a.off("update", this.onViewUpdate, this); + if (style instanceof this._styleClass) { + this._style = style; + } else { + this._style = new this._styleClass(style); + } + this._style.on("update", this.onViewUpdate, this); + this.onViewUpdate(); + } + /** + * The local bounds of the Text. + * @type {rendering.Bounds} + */ + get bounds() { + if (this._boundsDirty) { + this._updateBounds(); + this._boundsDirty = false; + } + return this._bounds; + } + /** The width of the sprite, setting this will actually modify the scale to achieve the value set. */ + get width() { + return Math.abs(this.scale.x) * this.bounds.width; + } + set width(value) { + this._setWidth(value, this.bounds.width); + } + /** The height of the sprite, setting this will actually modify the scale to achieve the value set. */ + get height() { + return Math.abs(this.scale.y) * this.bounds.height; + } + set height(value) { + this._setHeight(value, this.bounds.height); + } + /** + * Retrieves the size of the Text as a [Size]{@link Size} object. + * This is faster than get the width and height separately. + * @param out - Optional object to store the size in. + * @returns - The size of the Text. + */ + getSize(out) { + if (!out) { + out = {}; + } + out.width = Math.abs(this.scale.x) * this.bounds.width; + out.height = Math.abs(this.scale.y) * this.bounds.height; + return out; + } + /** + * Sets the size of the Text to the specified width and height. + * This is faster than setting the width and height separately. + * @param value - This can be either a number or a [Size]{@link Size} object. + * @param height - The height to set. Defaults to the value of `width` if not provided. + */ + setSize(value, height) { + var _a; + let convertedWidth; + let convertedHeight; + if (typeof value !== "object") { + convertedWidth = value; + convertedHeight = height != null ? height : value; + } else { + convertedWidth = value.width; + convertedHeight = (_a = value.height) != null ? _a : value.width; + } + if (convertedWidth !== void 0) { + this._setWidth(convertedWidth, this.bounds.width); + } + if (convertedHeight !== void 0) { + this._setHeight(convertedHeight, this.bounds.height); + } + } + /** + * Adds the bounds of this text to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + const _bounds = this.bounds; + bounds.addFrame( + _bounds.minX, + _bounds.minY, + _bounds.maxX, + _bounds.maxY + ); + } + /** + * Checks if the text contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + const width = this.bounds.width; + const height = this.bounds.height; + const x1 = -width * this.anchor.x; + let y1 = 0; + if (point.x >= x1 && point.x <= x1 + width) { + y1 = -height * this.anchor.y; + if (point.y >= y1 && point.y <= y1 + height) + return true; + } + return false; + } + onViewUpdate() { + this._didChangeId += 1 << 12; + this._boundsDirty = true; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + this._didTextUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + _getKey() { + return `${this.text}:${this._style.styleKey}-${this.resolution}`; + } + /** + * Destroys this text renderable and optionally its style texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the texture of the text style + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the text style + * @param {boolean} [options.style=false] - Should it destroy the style of the text + */ + destroy(options = false) { + super.destroy(options); + this.owner = null; + this._bounds = null; + this._anchor = null; + if (typeof options === "boolean" ? options : options == null ? void 0 : options.style) { + this._style.destroy(options); + } + this._style = null; + this._text = null; + } + } + function ensureOptions(args, name) { + var _a; + let options = (_a = args[0]) != null ? _a : {}; + if (typeof options === "string" || args[1]) { + deprecation(v8_0_0, `use new ${name}({ text: "hi!", style }) instead`); + options = { + text: options, + style: args[1] + }; + } + return options; + } + + "use strict"; + class Text extends AbstractText { + constructor(...args) { + const options = ensureOptions(args, "Text"); + super(options, TextStyle); + this.renderPipeId = "text"; + } + _updateBounds() { + const bounds = this._bounds; + const padding = this._style.padding; + const anchor = this._anchor; + const canvasMeasurement = CanvasTextMetrics.measureText( + this._text, + this._style + ); + const { width, height } = canvasMeasurement; + bounds.minX = -anchor._x * width - padding; + bounds.maxX = bounds.minX + width + padding * 2; + bounds.minY = -anchor._y * height - padding; + bounds.maxY = bounds.minY + height + padding * 2; + } + } + + "use strict"; + class PrepareQueue extends PrepareBase { + /** + * Resolve the given resource type and return an item for the queue + * @param source + * @param queue + */ + resolveQueueItem(source, queue) { + if (source instanceof Container) { + this.resolveContainerQueueItem(source, queue); + } else if (source instanceof TextureSource || source instanceof Texture) { + queue.push(source.source); + } else if (source instanceof GraphicsContext) { + queue.push(source); + } + return null; + } + /** + * Resolve the given container and return an item for the queue + * @param container + * @param queue + */ + resolveContainerQueueItem(container, queue) { + if (container instanceof Sprite || container instanceof TilingSprite || container instanceof Mesh) { + queue.push(container.texture.source); + } else if (container instanceof Text) { + queue.push(container); + } else if (container instanceof Graphics) { + queue.push(container.context); + } else if (container instanceof AnimatedSprite) { + container.textures.forEach((textureOrFrame) => { + if (textureOrFrame.source) { + queue.push(textureOrFrame.source); + } else { + queue.push(textureOrFrame.texture.source); + } + }); + } + } + /** + * Resolve the given graphics context and return an item for the queue + * @param graphicsContext + */ + resolveGraphicsContextQueueItem(graphicsContext) { + this.renderer.graphicsContext.getContextRenderData(graphicsContext); + const { instructions } = graphicsContext; + for (const instruction of instructions) { + if (instruction.action === "texture") { + const { image } = instruction.data; + return image.source; + } else if (instruction.action === "fill") { + const { texture } = instruction.data.style; + return texture.source; + } + } + return null; + } + } + + "use strict"; + class BitmapText extends AbstractText { + constructor(...args) { + var _a, _b, _c; + const options = ensureOptions(args, "BitmapText"); + (_a = options.style) != null ? _a : options.style = options.style || {}; + (_c = (_b = options.style).fill) != null ? _c : _b.fill = 16777215; + super(options, TextStyle); + this.renderPipeId = "bitmapText"; + } + _updateBounds() { + const bounds = this._bounds; + const padding = this._style.padding; + const anchor = this._anchor; + const bitmapMeasurement = BitmapFontManager.measureText(this.text, this._style); + const scale = bitmapMeasurement.scale; + const offset = bitmapMeasurement.offsetY * scale; + const width = bitmapMeasurement.width * scale; + const height = bitmapMeasurement.height * scale; + bounds.minX = -anchor._x * width - padding; + bounds.maxX = bounds.minX + width; + bounds.minY = -anchor._y * (height + offset) - padding; + bounds.maxY = bounds.minY + height; + } + } + + "use strict"; + class HTMLText extends AbstractText { + constructor(...args) { + const options = ensureOptions(args, "HtmlText"); + super(options, HTMLTextStyle); + this.renderPipeId = "htmlText"; + } + _updateBounds() { + const bounds = this._bounds; + const padding = this._style.padding; + const anchor = this._anchor; + const htmlMeasurement = measureHtmlText(this.text, this._style); + const { width, height } = htmlMeasurement; + bounds.minX = -anchor._x * width - padding; + bounds.maxX = bounds.minX + width; + bounds.minY = -anchor._y * height - padding; + bounds.maxY = bounds.minY + height; + } + } + + "use strict"; + class PrepareUpload extends PrepareQueue { + /** + * Upload the given queue item + * @param item + */ + uploadQueueItem(item) { + if (item instanceof TextureSource) { + this.uploadTextureSource(item); + } else if (item instanceof Text) { + this.uploadText(item); + } else if (item instanceof HTMLText) { + this.uploadHTMLText(item); + } else if (item instanceof BitmapText) { + this.uploadBitmapText(item); + } else if (item instanceof GraphicsContext) { + this.uploadGraphicsContext(item); + } + } + uploadTextureSource(textureSource) { + this.renderer.texture.initSource(textureSource); + } + uploadText(_text) { + this.renderer.renderPipes.text.initGpuText(_text); + } + uploadBitmapText(_text) { + this.renderer.renderPipes.bitmapText.initGpuText(_text); + } + uploadHTMLText(_text) { + this.renderer.renderPipes.htmlText.initGpuText(_text); + } + /** + * Resolve the given graphics context and return an item for the queue + * @param graphicsContext + */ + uploadGraphicsContext(graphicsContext) { + this.renderer.graphicsContext.getContextRenderData(graphicsContext); + const { instructions } = graphicsContext; + for (const instruction of instructions) { + if (instruction.action === "texture") { + const { image } = instruction.data; + this.uploadTextureSource(image.source); + } else if (instruction.action === "fill") { + const { texture } = instruction.data.style; + this.uploadTextureSource(texture.source); + } + } + return null; + } + } + + "use strict"; + class PrepareSystem extends PrepareUpload { + /** Destroys the plugin, don't use after this. */ + destroy() { + clearTimeout(this.timeout); + this.renderer = null; + this.queue = null; + this.resolves = null; + } + } + /** @ignore */ + PrepareSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "prepare" + }; + + "use strict"; + + "use strict"; + class GlBatchAdaptor { + constructor() { + this._didUpload = false; + this._tempState = State.for2d(); + } + init(batcherPipe) { + const maxTextures = maxRecommendedTextures(); + const glProgram = compileHighShaderGlProgram({ + name: "batch", + bits: [ + colorBitGl, + generateTextureBatchBitGl(maxTextures), + roundPixelsBitGl + ] + }); + this._shader = new Shader({ + glProgram, + resources: { + batchSamplers: getBatchSamplersUniformGroup(maxTextures) + } + }); + batcherPipe.renderer.runners.contextChange.add(this); + } + contextChange() { + this._didUpload = false; + } + start(batchPipe, geometry) { + const renderer = batchPipe.renderer; + renderer.shader.bind(this._shader, this._didUpload); + renderer.shader.updateUniformGroup(renderer.globalUniforms.uniformGroup); + renderer.geometry.bind(geometry, this._shader.glProgram); + } + execute(batchPipe, batch) { + const renderer = batchPipe.renderer; + this._didUpload = true; + this._tempState.blendMode = batch.blendMode; + renderer.state.set(this._tempState); + const textures = batch.textures.textures; + for (let i = 0; i < textures.length; i++) { + renderer.texture.bind(textures[i], i); + } + renderer.geometry.draw("triangle-list", batch.size, batch.start); + } + destroy() { + this._shader.destroy(true); + this._shader = null; + } + } + /** @ignore */ + GlBatchAdaptor.extension = { + type: [ + ExtensionType.WebGLPipesAdaptor + ], + name: "batch" + }; + + "use strict"; + function generateGPULayout(maxTextures) { + const gpuLayout = []; + let bindIndex = 0; + for (let i = 0; i < maxTextures; i++) { + gpuLayout[bindIndex] = { + texture: { + sampleType: "float", + viewDimension: "2d", + multisampled: false + }, + binding: bindIndex, + visibility: GPUShaderStage.FRAGMENT + }; + bindIndex++; + gpuLayout[bindIndex] = { + sampler: { + type: "filtering" + }, + binding: bindIndex, + visibility: GPUShaderStage.FRAGMENT + }; + bindIndex++; + } + return gpuLayout; + } + + "use strict"; + function generateLayout(maxTextures) { + const layout = {}; + let bindIndex = 0; + for (let i = 0; i < maxTextures; i++) { + layout[`textureSource${i + 1}`] = bindIndex++; + layout[`textureSampler${i + 1}`] = bindIndex++; + } + return layout; + } + + "use strict"; + const tempState = State.for2d(); + class GpuBatchAdaptor { + init() { + const gpuProgram = compileHighShaderGpuProgram({ + name: "batch", + bits: [ + colorBit, + generateTextureBatchBit(maxRecommendedTextures()), + roundPixelsBit + ] + }); + this._shader = new Shader({ + gpuProgram, + groups: { + // these will be dynamically allocated + } + }); + } + start(batchPipe, geometry) { + const renderer = batchPipe.renderer; + const encoder = renderer.encoder; + const program = this._shader.gpuProgram; + this._geometry = geometry; + encoder.setGeometry(geometry); + tempState.blendMode = "normal"; + renderer.pipeline.getPipeline( + geometry, + program, + tempState + ); + const globalUniformsBindGroup = renderer.globalUniforms.bindGroup; + encoder.resetBindGroup(1); + encoder.setBindGroup(0, globalUniformsBindGroup, program); + } + execute(batchPipe, batch) { + const program = this._shader.gpuProgram; + const renderer = batchPipe.renderer; + const encoder = renderer.encoder; + if (!batch.bindGroup) { + const textureBatch = batch.textures; + batch.bindGroup = getTextureBatchBindGroup(textureBatch.textures, textureBatch.count); + } + tempState.blendMode = batch.blendMode; + const gpuBindGroup = renderer.bindGroup.getBindGroup( + batch.bindGroup, + program, + 1 + ); + const pipeline = renderer.pipeline.getPipeline( + this._geometry, + program, + tempState + ); + batch.bindGroup._touch(renderer.textureGC.count); + encoder.setPipeline(pipeline); + encoder.renderPassEncoder.setBindGroup(1, gpuBindGroup); + encoder.renderPassEncoder.drawIndexed(batch.size, 1, batch.start); + } + destroy() { + this._shader.destroy(true); + this._shader = null; + } + } + /** @ignore */ + GpuBatchAdaptor.extension = { + type: [ + ExtensionType.WebGPUPipesAdaptor + ], + name: "batch" + }; + + "use strict"; + class BatcherPipe { + constructor(renderer, adaptor) { + this.state = State.for2d(); + this._batches = /* @__PURE__ */ Object.create(null); + this._geometries = /* @__PURE__ */ Object.create(null); + this.renderer = renderer; + this._adaptor = adaptor; + this._adaptor.init(this); + } + buildStart(instructionSet) { + if (!this._batches[instructionSet.uid]) { + const batcher = new Batcher(); + this._batches[instructionSet.uid] = batcher; + this._geometries[batcher.uid] = new BatchGeometry(); + } + this._activeBatch = this._batches[instructionSet.uid]; + this._activeGeometry = this._geometries[this._activeBatch.uid]; + this._activeBatch.begin(); + } + addToBatch(batchableObject) { + this._activeBatch.add(batchableObject); + } + break(instructionSet) { + this._activeBatch.break(instructionSet); + } + buildEnd(instructionSet) { + const activeBatch = this._activeBatch; + const geometry = this._activeGeometry; + activeBatch.finish(instructionSet); + geometry.indexBuffer.setDataWithSize(activeBatch.indexBuffer, activeBatch.indexSize, true); + geometry.buffers[0].setDataWithSize(activeBatch.attributeBuffer.float32View, activeBatch.attributeSize, false); + } + upload(instructionSet) { + const batcher = this._batches[instructionSet.uid]; + const geometry = this._geometries[batcher.uid]; + if (batcher.dirty) { + batcher.dirty = false; + geometry.buffers[0].update(batcher.attributeSize * 4); + } + } + execute(batch) { + if (batch.action === "startBatch") { + const batcher = batch.batcher; + const geometry = this._geometries[batcher.uid]; + this._adaptor.start(this, geometry); + } + this._adaptor.execute(this, batch); + } + destroy() { + this.state = null; + this.renderer = null; + this._adaptor.destroy(); + this._adaptor = null; + for (const i in this._batches) { + this._batches[i].destroy(); + } + this._batches = null; + for (const i in this._geometries) { + this._geometries[i].destroy(); + } + this._geometries = null; + } + } + /** @ignore */ + BatcherPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "batch" + }; + + "use strict"; + + "use strict"; + function formatShader(shader) { + const spl = shader.split(/([\n{}])/g).map((a) => a.trim()).filter((a) => a.length); + let indent = ""; + const formatted = spl.map((a) => { + let indentedLine = indent + a; + if (a === "{") { + indent += " "; + } else if (a === "}") { + indent = indent.substr(0, indent.length - 4); + indentedLine = indent + a; + } + return indentedLine; + }).join("\n"); + return formatted; + } + + "use strict"; + const textureBit = { + name: "texture-bit", + vertex: { + header: ( + /* wgsl */ + ` + + struct TextureUniforms { + uTextureMatrix:mat3x3, + } + + @group(2) @binding(2) var textureUniforms : TextureUniforms; + ` + ), + main: ( + /* wgsl */ + ` + uv = (textureUniforms.uTextureMatrix * vec3(uv, 1.0)).xy; + ` + ) + }, + fragment: { + header: ( + /* wgsl */ + ` + @group(2) @binding(0) var uTexture: texture_2d; + @group(2) @binding(1) var uSampler: sampler; + + + ` + ), + main: ( + /* wgsl */ + ` + outColor = textureSample(uTexture, uSampler, vUV); + ` + ) + } + }; + const textureBitGl = { + name: "texture-bit", + vertex: { + header: ( + /* glsl */ + ` + uniform mat3 uTextureMatrix; + ` + ), + main: ( + /* glsl */ + ` + uv = (uTextureMatrix * vec3(uv, 1.0)).xy; + ` + ) + }, + fragment: { + header: ( + /* glsl */ + ` + uniform sampler2D uTexture; + + + ` + ), + main: ( + /* glsl */ + ` + outColor = texture(uTexture, vUV); + ` + ) + } + }; + + "use strict"; + function buildInstructions(renderGroup, renderPipes) { + const root = renderGroup.root; + const instructionSet = renderGroup.instructionSet; + instructionSet.reset(); + renderPipes.batch.buildStart(instructionSet); + renderPipes.blendMode.buildStart(); + renderPipes.colorMask.buildStart(); + if (root.sortableChildren) { + root.sortChildren(); + } + collectAllRenderablesAdvanced(root, instructionSet, renderPipes, true); + renderPipes.batch.buildEnd(instructionSet); + renderPipes.blendMode.buildEnd(instructionSet); + } + function collectAllRenderables(container, instructionSet, rendererPipes) { + if (container.globalDisplayStatus < 7 || !container.includeInBuild) + return; + if (container.sortableChildren) { + container.sortChildren(); + } + if (container.isSimple) { + collectAllRenderablesSimple(container, instructionSet, rendererPipes); + } else { + collectAllRenderablesAdvanced(container, instructionSet, rendererPipes, false); + } + } + function collectAllRenderablesSimple(container, instructionSet, renderPipes) { + if (container.renderPipeId) { + renderPipes.blendMode.setBlendMode(container, container.groupBlendMode, instructionSet); + container.didViewUpdate = false; + const rp = renderPipes; + rp[container.renderPipeId].addRenderable(container, instructionSet); + } + if (!container.renderGroup) { + const children = container.children; + const length = children.length; + for (let i = 0; i < length; i++) { + collectAllRenderables(children[i], instructionSet, renderPipes); + } + } + } + function collectAllRenderablesAdvanced(container, instructionSet, renderPipes, isRoot) { + if (!isRoot && container.renderGroup) { + renderPipes.renderGroup.addRenderGroup(container.renderGroup, instructionSet); + } else { + for (let i = 0; i < container.effects.length; i++) { + const effect = container.effects[i]; + const pipe = renderPipes[effect.pipe]; + pipe.push(effect, container, instructionSet); + } + const renderPipeId = container.renderPipeId; + if (renderPipeId) { + renderPipes.blendMode.setBlendMode(container, container.groupBlendMode, instructionSet); + container.didViewUpdate = false; + const pipe = renderPipes[renderPipeId]; + pipe.addRenderable(container, instructionSet); + } + const children = container.children; + if (children.length) { + for (let i = 0; i < children.length; i++) { + collectAllRenderables(children[i], instructionSet, renderPipes); + } + } + for (let i = container.effects.length - 1; i >= 0; i--) { + const effect = container.effects[i]; + const pipe = renderPipes[effect.pipe]; + pipe.pop(effect, container, instructionSet); + } + } + } + + "use strict"; + const tempBounds$1 = new Bounds(); + class AlphaMaskEffect extends FilterEffect { + constructor() { + super(); + this.filters = [new MaskFilter({ + sprite: new Sprite(Texture.EMPTY) + })]; + } + get sprite() { + return this.filters[0].sprite; + } + set sprite(value) { + this.filters[0].sprite = value; + } + } + class AlphaMaskPipe { + constructor(renderer) { + this._activeMaskStage = []; + this._renderer = renderer; + } + push(mask, maskedContainer, instructionSet) { + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "alphaMask", + action: "pushMaskBegin", + mask, + canBundle: false, + maskedContainer + }); + if (mask.renderMaskToTexture) { + const maskContainer = mask.mask; + maskContainer.includeInBuild = true; + collectAllRenderables( + maskContainer, + instructionSet, + renderer.renderPipes + ); + maskContainer.includeInBuild = false; + } + renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "alphaMask", + action: "pushMaskEnd", + mask, + maskedContainer, + canBundle: false + }); + } + pop(mask, _maskedContainer, instructionSet) { + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "alphaMask", + action: "popMaskEnd", + mask, + canBundle: false + }); + } + execute(instruction) { + const renderer = this._renderer; + const renderMask = instruction.mask.renderMaskToTexture; + if (instruction.action === "pushMaskBegin") { + const filterEffect = BigPool.get(AlphaMaskEffect); + if (renderMask) { + instruction.mask.mask.measurable = true; + const bounds = getGlobalBounds(instruction.mask.mask, true, tempBounds$1); + instruction.mask.mask.measurable = false; + bounds.ceil(); + const filterTexture = TexturePool.getOptimalTexture( + bounds.width, + bounds.height, + 1, + false + ); + renderer.renderTarget.push(filterTexture, true); + renderer.globalUniforms.push({ + offset: bounds, + worldColor: 4294967295 + }); + const sprite = filterEffect.sprite; + sprite.texture = filterTexture; + sprite.worldTransform.tx = bounds.minX; + sprite.worldTransform.ty = bounds.minY; + this._activeMaskStage.push({ + filterEffect, + maskedContainer: instruction.maskedContainer, + filterTexture + }); + } else { + filterEffect.sprite = instruction.mask.mask; + this._activeMaskStage.push({ + filterEffect, + maskedContainer: instruction.maskedContainer + }); + } + } else if (instruction.action === "pushMaskEnd") { + const maskData = this._activeMaskStage[this._activeMaskStage.length - 1]; + if (renderMask) { + renderer.renderTarget.pop(); + renderer.globalUniforms.pop(); + } + renderer.filter.push({ + renderPipeId: "filter", + action: "pushFilter", + container: maskData.maskedContainer, + filterEffect: maskData.filterEffect, + canBundle: false + }); + } else if (instruction.action === "popMaskEnd") { + renderer.filter.pop(); + const maskData = this._activeMaskStage.pop(); + if (renderMask) { + TexturePool.returnTexture(maskData.filterTexture); + } + BigPool.return(maskData.filterEffect); + } + } + destroy() { + this._renderer = null; + this._activeMaskStage = null; + } + } + /** @ignore */ + AlphaMaskPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "alphaMask" + }; + + "use strict"; + class ColorMaskPipe { + constructor(renderer) { + this._colorStack = []; + this._colorStackIndex = 0; + this._currentColor = 0; + this._renderer = renderer; + } + buildStart() { + this._colorStack[0] = 15; + this._colorStackIndex = 1; + this._currentColor = 15; + } + push(mask, _container, instructionSet) { + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + const colorStack = this._colorStack; + colorStack[this._colorStackIndex] = colorStack[this._colorStackIndex - 1] & mask.mask; + const currentColor = this._colorStack[this._colorStackIndex]; + if (currentColor !== this._currentColor) { + this._currentColor = currentColor; + instructionSet.add({ + renderPipeId: "colorMask", + colorMask: currentColor, + canBundle: false + }); + } + this._colorStackIndex++; + } + pop(_mask, _container, instructionSet) { + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + const colorStack = this._colorStack; + this._colorStackIndex--; + const currentColor = colorStack[this._colorStackIndex - 1]; + if (currentColor !== this._currentColor) { + this._currentColor = currentColor; + instructionSet.add({ + renderPipeId: "colorMask", + colorMask: currentColor, + canBundle: false + }); + } + } + execute(instruction) { + const renderer = this._renderer; + renderer.colorMask.setMask(instruction.colorMask); + } + destroy() { + this._colorStack = null; + } + } + /** @ignore */ + ColorMaskPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "colorMask" + }; + + "use strict"; + class ScissorMask { + constructor(mask) { + this.priority = 0; + this.pipe = "scissorMask"; + this.mask = mask; + this.mask.renderable = false; + this.mask.measurable = false; + } + addBounds(bounds, skipUpdateTransform) { + addMaskBounds(this.mask, bounds, skipUpdateTransform); + } + addLocalBounds(bounds, localRoot) { + addMaskLocalBounds(this.mask, bounds, localRoot); + } + containsPoint(point, hitTestFn) { + const mask = this.mask; + return hitTestFn(mask, point); + } + reset() { + this.mask.measurable = true; + this.mask = null; + } + destroy() { + this.reset(); + } + } + + "use strict"; + class StencilMaskPipe { + constructor(renderer) { + // used when building and also when executing.. + this._maskStackHash = {}; + this._maskHash = /* @__PURE__ */ new WeakMap(); + this._renderer = renderer; + } + push(mask, _container, instructionSet) { + var _a, _b; + const effect = mask; + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + renderer.renderPipes.blendMode.setBlendMode(effect.mask, "none", instructionSet); + instructionSet.add({ + renderPipeId: "stencilMask", + action: "pushMaskBegin", + mask, + canBundle: false + }); + const maskContainer = effect.mask; + maskContainer.includeInBuild = true; + if (!this._maskHash.has(effect)) { + this._maskHash.set(effect, { + instructionsStart: 0, + instructionsLength: 0 + }); + } + const maskData = this._maskHash.get(effect); + maskData.instructionsStart = instructionSet.instructionSize; + collectAllRenderables( + maskContainer, + instructionSet, + renderer.renderPipes + ); + maskContainer.includeInBuild = false; + renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "stencilMask", + action: "pushMaskEnd", + mask, + canBundle: false + }); + const instructionsLength = instructionSet.instructionSize - maskData.instructionsStart - 1; + maskData.instructionsLength = instructionsLength; + const renderTargetUid = renderer.renderTarget.renderTarget.uid; + (_b = (_a = this._maskStackHash)[renderTargetUid]) != null ? _b : _a[renderTargetUid] = 0; + } + pop(mask, _container, instructionSet) { + const effect = mask; + const renderer = this._renderer; + renderer.renderPipes.batch.break(instructionSet); + renderer.renderPipes.blendMode.setBlendMode(effect.mask, "none", instructionSet); + instructionSet.add({ + renderPipeId: "stencilMask", + action: "popMaskBegin", + canBundle: false + }); + const maskData = this._maskHash.get(mask); + for (let i = 0; i < maskData.instructionsLength; i++) { + instructionSet.instructions[instructionSet.instructionSize++] = instructionSet.instructions[maskData.instructionsStart++]; + } + instructionSet.add({ + renderPipeId: "stencilMask", + action: "popMaskEnd", + canBundle: false + }); + } + execute(instruction) { + var _a, _b; + const renderer = this._renderer; + const renderTargetUid = renderer.renderTarget.renderTarget.uid; + let maskStackIndex = (_b = (_a = this._maskStackHash)[renderTargetUid]) != null ? _b : _a[renderTargetUid] = 0; + if (instruction.action === "pushMaskBegin") { + renderer.renderTarget.ensureDepthStencil(); + renderer.stencil.setStencilMode(STENCIL_MODES.RENDERING_MASK_ADD, maskStackIndex); + maskStackIndex++; + renderer.colorMask.setMask(0); + } else if (instruction.action === "pushMaskEnd") { + renderer.stencil.setStencilMode(STENCIL_MODES.MASK_ACTIVE, maskStackIndex); + renderer.colorMask.setMask(15); + } else if (instruction.action === "popMaskBegin") { + renderer.colorMask.setMask(0); + if (maskStackIndex !== 0) { + renderer.stencil.setStencilMode(STENCIL_MODES.RENDERING_MASK_REMOVE, maskStackIndex); + } else { + renderer.renderTarget.clear(null, CLEAR.STENCIL); + renderer.stencil.setStencilMode(STENCIL_MODES.DISABLED, maskStackIndex); + } + maskStackIndex--; + } else if (instruction.action === "popMaskEnd") { + renderer.stencil.setStencilMode(STENCIL_MODES.MASK_ACTIVE, maskStackIndex); + renderer.colorMask.setMask(15); + } + this._maskStackHash[renderTargetUid] = maskStackIndex; + } + destroy() { + this._renderer = null; + this._maskStackHash = null; + this._maskHash = null; + } + } + StencilMaskPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "stencilMask" + }; + + "use strict"; + var BUFFER_TYPE = /* @__PURE__ */ ((BUFFER_TYPE2) => { + BUFFER_TYPE2[BUFFER_TYPE2["ELEMENT_ARRAY_BUFFER"] = 34963] = "ELEMENT_ARRAY_BUFFER"; + BUFFER_TYPE2[BUFFER_TYPE2["ARRAY_BUFFER"] = 34962] = "ARRAY_BUFFER"; + BUFFER_TYPE2[BUFFER_TYPE2["UNIFORM_BUFFER"] = 35345] = "UNIFORM_BUFFER"; + return BUFFER_TYPE2; + })(BUFFER_TYPE || {}); + + "use strict"; + class GlBuffer { + constructor(buffer, type) { + this.buffer = buffer || null; + this.updateID = -1; + this.byteLength = -1; + this.type = type; + } + } + + "use strict"; + class GlBufferSystem { + /** + * @param {Renderer} renderer - The renderer this System works for. + */ + constructor(renderer) { + this._gpuBuffers = /* @__PURE__ */ Object.create(null); + /** Cache keeping track of the base bound buffer bases */ + this._boundBufferBases = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + /** + * @ignore + */ + destroy() { + this._renderer = null; + this._gl = null; + this._gpuBuffers = null; + this._boundBufferBases = null; + } + /** Sets up the renderer context and necessary buffers. */ + contextChange() { + this._gpuBuffers = /* @__PURE__ */ Object.create(null); + this._gl = this._renderer.gl; + } + getGlBuffer(buffer) { + return this._gpuBuffers[buffer.uid] || this.createGLBuffer(buffer); + } + /** + * This binds specified buffer. On first run, it will create the webGL buffers for the context too + * @param buffer - the buffer to bind to the renderer + */ + bind(buffer) { + const { _gl: gl } = this; + const glBuffer = this.getGlBuffer(buffer); + gl.bindBuffer(glBuffer.type, glBuffer.buffer); + } + /** + * Binds an uniform buffer to at the given index. + * + * A cache is used so a buffer will not be bound again if already bound. + * @param buffer - the buffer to bind + * @param index - the base index to bind it to. + */ + bindBufferBase(buffer, index) { + const { _gl: gl } = this; + if (this._boundBufferBases[index] !== buffer) { + const glBuffer = this.getGlBuffer(buffer); + this._boundBufferBases[index] = buffer; + gl.bindBufferBase(gl.UNIFORM_BUFFER, index, glBuffer.buffer); + } + } + /** + * Binds a buffer whilst also binding its range. + * This will make the buffer start from the offset supplied rather than 0 when it is read. + * @param buffer - the buffer to bind + * @param index - the base index to bind at, defaults to 0 + * @param offset - the offset to bind at (this is blocks of 256). 0 = 0, 1 = 256, 2 = 512 etc + */ + bindBufferRange(buffer, index, offset) { + const { _gl: gl } = this; + offset = offset || 0; + const glBuffer = this.getGlBuffer(buffer); + gl.bindBufferRange(gl.UNIFORM_BUFFER, index || 0, glBuffer.buffer, offset * 256, 256); + } + /** + * Will ensure the data in the buffer is uploaded to the GPU. + * @param {Buffer} buffer - the buffer to update + */ + updateBuffer(buffer) { + const { _gl: gl } = this; + const glBuffer = this.getGlBuffer(buffer); + if (buffer._updateID === glBuffer.updateID) { + return glBuffer; + } + glBuffer.updateID = buffer._updateID; + gl.bindBuffer(glBuffer.type, glBuffer.buffer); + const data = buffer.data; + if (glBuffer.byteLength >= buffer.data.byteLength) { + gl.bufferSubData(glBuffer.type, 0, data, 0, buffer._updateSize / data.BYTES_PER_ELEMENT); + } else { + const drawType = buffer.descriptor.usage & BufferUsage.STATIC ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW; + glBuffer.byteLength = data.byteLength; + gl.bufferData(glBuffer.type, data, drawType); + } + return glBuffer; + } + /** dispose all WebGL resources of all managed buffers */ + destroyAll() { + const gl = this._gl; + for (const id in this._gpuBuffers) { + gl.deleteBuffer(this._gpuBuffers[id].buffer); + } + this._gpuBuffers = /* @__PURE__ */ Object.create(null); + } + /** + * Disposes buffer + * @param {Buffer} buffer - buffer with data + * @param {boolean} [contextLost=false] - If context was lost, we suppress deleteVertexArray + */ + onBufferDestroy(buffer, contextLost) { + const glBuffer = this._gpuBuffers[buffer.uid]; + const gl = this._gl; + if (!contextLost) { + gl.deleteBuffer(glBuffer.buffer); + } + this._gpuBuffers[buffer.uid] = null; + } + /** + * creates and attaches a GLBuffer object tied to the current context. + * @param buffer + * @protected + */ + createGLBuffer(buffer) { + const { _gl: gl } = this; + let type = BUFFER_TYPE.ARRAY_BUFFER; + if (buffer.descriptor.usage & BufferUsage.INDEX) { + type = BUFFER_TYPE.ELEMENT_ARRAY_BUFFER; + } else if (buffer.descriptor.usage & BufferUsage.UNIFORM) { + type = BUFFER_TYPE.UNIFORM_BUFFER; + } + const glBuffer = new GlBuffer(gl.createBuffer(), type); + this._gpuBuffers[buffer.uid] = glBuffer; + buffer.on("destroy", this.onBufferDestroy, this); + return glBuffer; + } + } + /** @ignore */ + GlBufferSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "buffer" + }; + + "use strict"; + var __defProp$j = Object.defineProperty; + var __defProps$8 = Object.defineProperties; + var __getOwnPropDescs$8 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$j = Object.getOwnPropertySymbols; + var __hasOwnProp$j = Object.prototype.hasOwnProperty; + var __propIsEnum$j = Object.prototype.propertyIsEnumerable; + var __defNormalProp$j = (obj, key, value) => key in obj ? __defProp$j(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$j = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$j.call(b, prop)) + __defNormalProp$j(a, prop, b[prop]); + if (__getOwnPropSymbols$j) + for (var prop of __getOwnPropSymbols$j(b)) { + if (__propIsEnum$j.call(b, prop)) + __defNormalProp$j(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$8 = (a, b) => __defProps$8(a, __getOwnPropDescs$8(b)); + const _GlContextSystem = class _GlContextSystem { + /** @param renderer - The renderer this System works for. */ + constructor(renderer) { + /** + * Features supported by current renderer. + * @type {object} + * @readonly + */ + this.supports = { + /** Support for 32-bit indices buffer. */ + uint32Indices: true, + /** Support for UniformBufferObjects */ + uniformBufferObject: true, + /** Support for VertexArrayObjects */ + vertexArrayObject: true, + /** Support for SRGB texture format */ + srgbTextures: true, + /** Support for wrapping modes if a texture is non-power of two */ + nonPowOf2wrapping: true, + /** Support for MSAA (antialiasing of dynamic textures) */ + msaa: true, + /** Support for mipmaps if a texture is non-power of two */ + nonPowOf2mipmaps: true + }; + this._renderer = renderer; + this.extensions = /* @__PURE__ */ Object.create(null); + this.handleContextLost = this.handleContextLost.bind(this); + this.handleContextRestored = this.handleContextRestored.bind(this); + } + /** + * `true` if the context is lost + * @readonly + */ + get isLost() { + return !this.gl || this.gl.isContextLost(); + } + /** + * Handles the context change event. + * @param {WebGLRenderingContext} gl - New WebGL context. + */ + contextChange(gl) { + this.gl = gl; + this._renderer.gl = gl; + } + init(options) { + var _a, _b; + options = __spreadValues$j(__spreadValues$j({}, _GlContextSystem.defaultOptions), options); + if (options.context) { + this.initFromContext(options.context); + } else { + const alpha = this._renderer.background.alpha < 1; + const premultipliedAlpha = (_a = options.premultipliedAlpha) != null ? _a : true; + const antialias = options.antialias && !this._renderer.backBuffer.useBackBuffer; + this.createContext(options.preferWebGLVersion, { + alpha, + premultipliedAlpha, + antialias, + stencil: true, + preserveDrawingBuffer: options.preserveDrawingBuffer, + powerPreference: (_b = options.powerPreference) != null ? _b : "default" + }); + } + } + /** + * Initializes the context. + * @protected + * @param {WebGLRenderingContext} gl - WebGL context + */ + initFromContext(gl) { + this.gl = gl; + this.webGLVersion = gl instanceof DOMAdapter.get().getWebGLRenderingContext() ? 1 : 2; + this.getExtensions(); + this.validateContext(gl); + this._renderer.runners.contextChange.emit(gl); + const element = this._renderer.view.canvas; + element.addEventListener("webglcontextlost", this.handleContextLost, false); + element.addEventListener("webglcontextrestored", this.handleContextRestored, false); + } + /** + * Initialize from context options + * @protected + * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext + * @param preferWebGLVersion + * @param {object} options - context attributes + */ + createContext(preferWebGLVersion, options) { + let gl; + const canvas = this._renderer.view.canvas; + if (preferWebGLVersion === 2) { + gl = canvas.getContext("webgl2", options); + } + if (!gl) { + gl = canvas.getContext("webgl", options); + if (!gl) { + throw new Error("This browser does not support WebGL. Try using the canvas renderer"); + } + } + this.gl = gl; + this.initFromContext(this.gl); + } + /** Auto-populate the {@link GlContextSystem.extensions extensions}. */ + getExtensions() { + const { gl } = this; + const common = { + anisotropicFiltering: gl.getExtension("EXT_texture_filter_anisotropic"), + floatTextureLinear: gl.getExtension("OES_texture_float_linear"), + s3tc: gl.getExtension("WEBGL_compressed_texture_s3tc"), + s3tc_sRGB: gl.getExtension("WEBGL_compressed_texture_s3tc_srgb"), + // eslint-disable-line camelcase + etc: gl.getExtension("WEBGL_compressed_texture_etc"), + etc1: gl.getExtension("WEBGL_compressed_texture_etc1"), + pvrtc: gl.getExtension("WEBGL_compressed_texture_pvrtc") || gl.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"), + atc: gl.getExtension("WEBGL_compressed_texture_atc"), + astc: gl.getExtension("WEBGL_compressed_texture_astc"), + bptc: gl.getExtension("EXT_texture_compression_bptc"), + rgtc: gl.getExtension("EXT_texture_compression_rgtc"), + loseContext: gl.getExtension("WEBGL_lose_context") + }; + if (this.webGLVersion === 1) { + this.extensions = __spreadProps$8(__spreadValues$j({}, common), { + drawBuffers: gl.getExtension("WEBGL_draw_buffers"), + depthTexture: gl.getExtension("WEBGL_depth_texture"), + vertexArrayObject: gl.getExtension("OES_vertex_array_object") || gl.getExtension("MOZ_OES_vertex_array_object") || gl.getExtension("WEBKIT_OES_vertex_array_object"), + uint32ElementIndex: gl.getExtension("OES_element_index_uint"), + // Floats and half-floats + floatTexture: gl.getExtension("OES_texture_float"), + floatTextureLinear: gl.getExtension("OES_texture_float_linear"), + textureHalfFloat: gl.getExtension("OES_texture_half_float"), + textureHalfFloatLinear: gl.getExtension("OES_texture_half_float_linear"), + vertexAttribDivisorANGLE: gl.getExtension("ANGLE_instanced_arrays"), + srgb: gl.getExtension("EXT_sRGB") + }); + } else { + this.extensions = __spreadProps$8(__spreadValues$j({}, common), { + colorBufferFloat: gl.getExtension("EXT_color_buffer_float") + }); + const provokeExt = gl.getExtension("WEBGL_provoking_vertex"); + if (provokeExt) { + provokeExt.provokingVertexWEBGL(provokeExt.FIRST_VERTEX_CONVENTION_WEBGL); + } + } + } + /** + * Handles a lost webgl context + * @param {WebGLContextEvent} event - The context lost event. + */ + handleContextLost(event) { + event.preventDefault(); + if (this._contextLossForced) { + this._contextLossForced = false; + setTimeout(() => { + var _a; + if (this.gl.isContextLost()) { + (_a = this.extensions.loseContext) == null ? void 0 : _a.restoreContext(); + } + }, 0); + } + } + /** Handles a restored webgl context. */ + handleContextRestored() { + this._renderer.runners.contextChange.emit(this.gl); + } + destroy() { + var _a; + const element = this._renderer.view.canvas; + this._renderer = null; + element.removeEventListener("webglcontextlost", this.handleContextLost); + element.removeEventListener("webglcontextrestored", this.handleContextRestored); + this.gl.useProgram(null); + (_a = this.extensions.loseContext) == null ? void 0 : _a.loseContext(); + } + /** + * this function can be called to force a webGL context loss + * this will release all resources on the GPU. + * Useful if you need to put Pixi to sleep, and save some GPU memory + * + * As soon as render is called - all resources will be created again. + */ + forceContextLoss() { + var _a; + (_a = this.extensions.loseContext) == null ? void 0 : _a.loseContext(); + this._contextLossForced = true; + } + /** + * Validate context. + * @param {WebGLRenderingContext} gl - Render context. + */ + validateContext(gl) { + const attributes = gl.getContextAttributes(); + if (attributes && !attributes.stencil) { + warn("Provided WebGL context does not have a stencil buffer, masks may not render correctly"); + } + const supports = this.supports; + const isWebGl2 = this.webGLVersion === 2; + const extensions = this.extensions; + supports.uint32Indices = isWebGl2 || !!extensions.uint32ElementIndex; + supports.uniformBufferObject = isWebGl2; + supports.vertexArrayObject = isWebGl2 || !!extensions.vertexArrayObject; + supports.srgbTextures = isWebGl2 || !!extensions.srgb; + supports.nonPowOf2wrapping = isWebGl2; + supports.nonPowOf2mipmaps = isWebGl2; + supports.msaa = isWebGl2; + if (!supports.uint32Indices) { + warn("Provided WebGL context does not support 32 index buffer, large scenes may not render correctly"); + } + } + }; + /** @ignore */ + _GlContextSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "context" + }; + /** The default options for the system. */ + _GlContextSystem.defaultOptions = { + /** + * {@link WebGLOptions.context} + * @default null + */ + context: null, + /** + * {@link WebGLOptions.premultipliedAlpha} + * @default true + */ + premultipliedAlpha: true, + /** + * {@link WebGLOptions.preserveDrawingBuffer} + * @default false + */ + preserveDrawingBuffer: false, + /** + * {@link WebGLOptions.powerPreference} + * @default default + */ + powerPreference: void 0, + /** + * {@link WebGLOptions.webGLVersion} + * @default 2 + */ + preferWebGLVersion: 2 + }; + let GlContextSystem = _GlContextSystem; + + "use strict"; + + "use strict"; + + "use strict"; + function ensureAttributes(geometry, extractedData) { + var _a, _b, _c, _d; + for (const i in geometry.attributes) { + const attribute = geometry.attributes[i]; + const attributeData = extractedData[i]; + if (attributeData) { + (_a = attribute.location) != null ? _a : attribute.location = attributeData.location; + (_b = attribute.format) != null ? _b : attribute.format = attributeData.format; + (_c = attribute.offset) != null ? _c : attribute.offset = attributeData.offset; + (_d = attribute.instance) != null ? _d : attribute.instance = attributeData.instance; + } else { + warn(`Attribute ${i} is not present in the shader, but is present in the geometry. Unable to infer attribute details.`); + } + } + ensureStartAndStride(geometry); + } + function ensureStartAndStride(geometry) { + var _a, _b; + const { buffers, attributes } = geometry; + const tempStride = {}; + const tempStart = {}; + for (const j in buffers) { + const buffer = buffers[j]; + tempStride[buffer.uid] = 0; + tempStart[buffer.uid] = 0; + } + for (const j in attributes) { + const attribute = attributes[j]; + tempStride[attribute.buffer.uid] += getAttributeInfoFromFormat(attribute.format).stride; + } + for (const j in attributes) { + const attribute = attributes[j]; + (_a = attribute.stride) != null ? _a : attribute.stride = tempStride[attribute.buffer.uid]; + (_b = attribute.start) != null ? _b : attribute.start = tempStart[attribute.buffer.uid]; + tempStart[attribute.buffer.uid] += getAttributeInfoFromFormat(attribute.format).stride; + } + } + + "use strict"; + var GL_FORMATS = /* @__PURE__ */ ((GL_FORMATS2) => { + GL_FORMATS2[GL_FORMATS2["RGBA"] = 6408] = "RGBA"; + GL_FORMATS2[GL_FORMATS2["RGB"] = 6407] = "RGB"; + GL_FORMATS2[GL_FORMATS2["RG"] = 33319] = "RG"; + GL_FORMATS2[GL_FORMATS2["RED"] = 6403] = "RED"; + GL_FORMATS2[GL_FORMATS2["RGBA_INTEGER"] = 36249] = "RGBA_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RGB_INTEGER"] = 36248] = "RGB_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RG_INTEGER"] = 33320] = "RG_INTEGER"; + GL_FORMATS2[GL_FORMATS2["RED_INTEGER"] = 36244] = "RED_INTEGER"; + GL_FORMATS2[GL_FORMATS2["ALPHA"] = 6406] = "ALPHA"; + GL_FORMATS2[GL_FORMATS2["LUMINANCE"] = 6409] = "LUMINANCE"; + GL_FORMATS2[GL_FORMATS2["LUMINANCE_ALPHA"] = 6410] = "LUMINANCE_ALPHA"; + GL_FORMATS2[GL_FORMATS2["DEPTH_COMPONENT"] = 6402] = "DEPTH_COMPONENT"; + GL_FORMATS2[GL_FORMATS2["DEPTH_STENCIL"] = 34041] = "DEPTH_STENCIL"; + return GL_FORMATS2; + })(GL_FORMATS || {}); + var GL_TARGETS = /* @__PURE__ */ ((GL_TARGETS2) => { + GL_TARGETS2[GL_TARGETS2["TEXTURE_2D"] = 3553] = "TEXTURE_2D"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP"] = 34067] = "TEXTURE_CUBE_MAP"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_2D_ARRAY"] = 35866] = "TEXTURE_2D_ARRAY"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_POSITIVE_X"] = 34069] = "TEXTURE_CUBE_MAP_POSITIVE_X"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_NEGATIVE_X"] = 34070] = "TEXTURE_CUBE_MAP_NEGATIVE_X"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_POSITIVE_Y"] = 34071] = "TEXTURE_CUBE_MAP_POSITIVE_Y"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_NEGATIVE_Y"] = 34072] = "TEXTURE_CUBE_MAP_NEGATIVE_Y"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_POSITIVE_Z"] = 34073] = "TEXTURE_CUBE_MAP_POSITIVE_Z"; + GL_TARGETS2[GL_TARGETS2["TEXTURE_CUBE_MAP_NEGATIVE_Z"] = 34074] = "TEXTURE_CUBE_MAP_NEGATIVE_Z"; + return GL_TARGETS2; + })(GL_TARGETS || {}); + var GL_WRAP_MODES = /* @__PURE__ */ ((GL_WRAP_MODES2) => { + GL_WRAP_MODES2[GL_WRAP_MODES2["CLAMP"] = 33071] = "CLAMP"; + GL_WRAP_MODES2[GL_WRAP_MODES2["REPEAT"] = 10497] = "REPEAT"; + GL_WRAP_MODES2[GL_WRAP_MODES2["MIRRORED_REPEAT"] = 33648] = "MIRRORED_REPEAT"; + return GL_WRAP_MODES2; + })(GL_WRAP_MODES || {}); + var GL_TYPES = /* @__PURE__ */ ((GL_TYPES2) => { + GL_TYPES2[GL_TYPES2["UNSIGNED_BYTE"] = 5121] = "UNSIGNED_BYTE"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT"] = 5123] = "UNSIGNED_SHORT"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_5_6_5"] = 33635] = "UNSIGNED_SHORT_5_6_5"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_4_4_4_4"] = 32819] = "UNSIGNED_SHORT_4_4_4_4"; + GL_TYPES2[GL_TYPES2["UNSIGNED_SHORT_5_5_5_1"] = 32820] = "UNSIGNED_SHORT_5_5_5_1"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT"] = 5125] = "UNSIGNED_INT"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_10F_11F_11F_REV"] = 35899] = "UNSIGNED_INT_10F_11F_11F_REV"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_2_10_10_10_REV"] = 33640] = "UNSIGNED_INT_2_10_10_10_REV"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_24_8"] = 34042] = "UNSIGNED_INT_24_8"; + GL_TYPES2[GL_TYPES2["UNSIGNED_INT_5_9_9_9_REV"] = 35902] = "UNSIGNED_INT_5_9_9_9_REV"; + GL_TYPES2[GL_TYPES2["BYTE"] = 5120] = "BYTE"; + GL_TYPES2[GL_TYPES2["SHORT"] = 5122] = "SHORT"; + GL_TYPES2[GL_TYPES2["INT"] = 5124] = "INT"; + GL_TYPES2[GL_TYPES2["FLOAT"] = 5126] = "FLOAT"; + GL_TYPES2[GL_TYPES2["FLOAT_32_UNSIGNED_INT_24_8_REV"] = 36269] = "FLOAT_32_UNSIGNED_INT_24_8_REV"; + GL_TYPES2[GL_TYPES2["HALF_FLOAT"] = 36193] = "HALF_FLOAT"; + return GL_TYPES2; + })(GL_TYPES || {}); + + "use strict"; + const infoMap = { + uint8x2: GL_TYPES.UNSIGNED_BYTE, + uint8x4: GL_TYPES.UNSIGNED_BYTE, + sint8x2: GL_TYPES.BYTE, + sint8x4: GL_TYPES.BYTE, + unorm8x2: GL_TYPES.UNSIGNED_BYTE, + unorm8x4: GL_TYPES.UNSIGNED_BYTE, + snorm8x2: GL_TYPES.BYTE, + snorm8x4: GL_TYPES.BYTE, + uint16x2: GL_TYPES.UNSIGNED_SHORT, + uint16x4: GL_TYPES.UNSIGNED_SHORT, + sint16x2: GL_TYPES.SHORT, + sint16x4: GL_TYPES.SHORT, + unorm16x2: GL_TYPES.UNSIGNED_SHORT, + unorm16x4: GL_TYPES.UNSIGNED_SHORT, + snorm16x2: GL_TYPES.SHORT, + snorm16x4: GL_TYPES.SHORT, + float16x2: GL_TYPES.HALF_FLOAT, + float16x4: GL_TYPES.HALF_FLOAT, + float32: GL_TYPES.FLOAT, + float32x2: GL_TYPES.FLOAT, + float32x3: GL_TYPES.FLOAT, + float32x4: GL_TYPES.FLOAT, + uint32: GL_TYPES.UNSIGNED_INT, + uint32x2: GL_TYPES.UNSIGNED_INT, + uint32x3: GL_TYPES.UNSIGNED_INT, + uint32x4: GL_TYPES.UNSIGNED_INT, + sint32: GL_TYPES.INT, + sint32x2: GL_TYPES.INT, + sint32x3: GL_TYPES.INT, + sint32x4: GL_TYPES.INT + }; + function getGlTypeFromFormat(format) { + var _a; + return (_a = infoMap[format]) != null ? _a : infoMap.float32; + } + + "use strict"; + const topologyToGlMap = { + "point-list": 0, + "line-list": 1, + "line-strip": 3, + "triangle-list": 4, + "triangle-strip": 5 + }; + class GlGeometrySystem { + /** @param renderer - The renderer this System works for. */ + constructor(renderer) { + this._geometryVaoHash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + this._activeGeometry = null; + this._activeVao = null; + this.hasVao = true; + this.hasInstance = true; + } + /** Sets up the renderer context and necessary buffers. */ + contextChange() { + const gl = this.gl = this._renderer.gl; + if (!this._renderer.context.supports.vertexArrayObject) { + throw new Error("[PixiJS] Vertex Array Objects are not supported on this device"); + } + const nativeVaoExtension = this._renderer.context.extensions.vertexArrayObject; + if (nativeVaoExtension) { + gl.createVertexArray = () => nativeVaoExtension.createVertexArrayOES(); + gl.bindVertexArray = (vao) => nativeVaoExtension.bindVertexArrayOES(vao); + gl.deleteVertexArray = (vao) => nativeVaoExtension.deleteVertexArrayOES(vao); + } + const nativeInstancedExtension = this._renderer.context.extensions.vertexAttribDivisorANGLE; + if (nativeInstancedExtension) { + gl.drawArraysInstanced = (a, b, c, d) => { + nativeInstancedExtension.drawArraysInstancedANGLE(a, b, c, d); + }; + gl.drawElementsInstanced = (a, b, c, d, e) => { + nativeInstancedExtension.drawElementsInstancedANGLE(a, b, c, d, e); + }; + gl.vertexAttribDivisor = (a, b) => nativeInstancedExtension.vertexAttribDivisorANGLE(a, b); + } + this._activeGeometry = null; + this._activeVao = null; + this._geometryVaoHash = /* @__PURE__ */ Object.create(null); + } + /** + * Binds geometry so that is can be drawn. Creating a Vao if required + * @param geometry - Instance of geometry to bind. + * @param program - Instance of program to use vao for. + */ + bind(geometry, program) { + const gl = this.gl; + this._activeGeometry = geometry; + const vao = this.getVao(geometry, program); + if (this._activeVao !== vao) { + this._activeVao = vao; + gl.bindVertexArray(vao); + } + this.updateBuffers(); + } + /** Reset and unbind any active VAO and geometry. */ + reset() { + this.unbind(); + } + /** Update buffers of the currently bound geometry. */ + updateBuffers() { + const geometry = this._activeGeometry; + const bufferSystem = this._renderer.buffer; + for (let i = 0; i < geometry.buffers.length; i++) { + const buffer = geometry.buffers[i]; + bufferSystem.updateBuffer(buffer); + } + } + /** + * Check compatibility between a geometry and a program + * @param geometry - Geometry instance. + * @param program - Program instance. + */ + checkCompatibility(geometry, program) { + const geometryAttributes = geometry.attributes; + const shaderAttributes = program._attributeData; + for (const j in shaderAttributes) { + if (!geometryAttributes[j]) { + throw new Error(`shader and geometry incompatible, geometry missing the "${j}" attribute`); + } + } + } + /** + * Takes a geometry and program and generates a unique signature for them. + * @param geometry - To get signature from. + * @param program - To test geometry against. + * @returns - Unique signature of the geometry and program + */ + getSignature(geometry, program) { + const attribs = geometry.attributes; + const shaderAttributes = program._attributeData; + const strings = ["g", geometry.uid]; + for (const i in attribs) { + if (shaderAttributes[i]) { + strings.push(i, shaderAttributes[i].location); + } + } + return strings.join("-"); + } + getVao(geometry, program) { + var _a; + return ((_a = this._geometryVaoHash[geometry.uid]) == null ? void 0 : _a[program._key]) || this.initGeometryVao(geometry, program); + } + /** + * Creates or gets Vao with the same structure as the geometry and stores it on the geometry. + * If vao is created, it is bound automatically. We use a shader to infer what and how to set up the + * attribute locations. + * @param geometry - Instance of geometry to to generate Vao for. + * @param program + * @param _incRefCount - Increment refCount of all geometry buffers. + */ + initGeometryVao(geometry, program, _incRefCount = true) { + const gl = this._renderer.gl; + const bufferSystem = this._renderer.buffer; + this._renderer.shader._getProgramData(program); + this.checkCompatibility(geometry, program); + const signature = this.getSignature(geometry, program); + if (!this._geometryVaoHash[geometry.uid]) { + this._geometryVaoHash[geometry.uid] = /* @__PURE__ */ Object.create(null); + geometry.on("destroy", this.onGeometryDestroy, this); + } + const vaoObjectHash = this._geometryVaoHash[geometry.uid]; + let vao = vaoObjectHash[signature]; + if (vao) { + vaoObjectHash[program._key] = vao; + return vao; + } + ensureAttributes(geometry, program._attributeData); + const buffers = geometry.buffers; + vao = gl.createVertexArray(); + gl.bindVertexArray(vao); + for (let i = 0; i < buffers.length; i++) { + const buffer = buffers[i]; + bufferSystem.bind(buffer); + } + this.activateVao(geometry, program); + vaoObjectHash[program._key] = vao; + vaoObjectHash[signature] = vao; + gl.bindVertexArray(null); + return vao; + } + /** + * Disposes geometry. + * @param geometry - Geometry with buffers. Only VAO will be disposed + * @param [contextLost=false] - If context was lost, we suppress deleteVertexArray + */ + onGeometryDestroy(geometry, contextLost) { + const vaoObjectHash = this._geometryVaoHash[geometry.uid]; + const gl = this.gl; + if (vaoObjectHash) { + if (contextLost) { + for (const i in vaoObjectHash) { + if (this._activeVao !== vaoObjectHash[i]) { + this.unbind(); + } + gl.deleteVertexArray(vaoObjectHash[i]); + } + } + this._geometryVaoHash[geometry.uid] = null; + } + } + /** + * Dispose all WebGL resources of all managed geometries. + * @param [contextLost=false] - If context was lost, we suppress `gl.delete` calls + */ + destroyAll(contextLost = false) { + const gl = this.gl; + for (const i in this._geometryVaoHash) { + if (contextLost) { + for (const j in this._geometryVaoHash[i]) { + const vaoObjectHash = this._geometryVaoHash[i]; + if (this._activeVao !== vaoObjectHash) { + this.unbind(); + } + gl.deleteVertexArray(vaoObjectHash[j]); + } + } + this._geometryVaoHash[i] = null; + } + } + /** + * Activate vertex array object. + * @param geometry - Geometry instance. + * @param program - Shader program instance. + */ + activateVao(geometry, program) { + var _a; + const gl = this._renderer.gl; + const bufferSystem = this._renderer.buffer; + const attributes = geometry.attributes; + if (geometry.indexBuffer) { + bufferSystem.bind(geometry.indexBuffer); + } + let lastBuffer = null; + for (const j in attributes) { + const attribute = attributes[j]; + const buffer = attribute.buffer; + const glBuffer = bufferSystem.getGlBuffer(buffer); + const programAttrib = program._attributeData[j]; + if (programAttrib) { + if (lastBuffer !== glBuffer) { + bufferSystem.bind(buffer); + lastBuffer = glBuffer; + } + const location = attribute.location; + gl.enableVertexAttribArray(location); + const attributeInfo = getAttributeInfoFromFormat(attribute.format); + const type = getGlTypeFromFormat(attribute.format); + if (((_a = programAttrib.format) == null ? void 0 : _a.substring(1, 4)) === "int") { + gl.vertexAttribIPointer( + location, + attributeInfo.size, + type, + attribute.stride, + attribute.offset + ); + } else { + gl.vertexAttribPointer( + location, + attributeInfo.size, + type, + attributeInfo.normalised, + attribute.stride, + attribute.offset + ); + } + if (attribute.instance) { + if (this.hasInstance) { + gl.vertexAttribDivisor(location, 1); + } else { + throw new Error("geometry error, GPU Instancing is not supported on this device"); + } + } + } + } + } + /** + * Draws the currently bound geometry. + * @param topology - The type primitive to render. + * @param size - The number of elements to be rendered. If not specified, all vertices after the + * starting vertex will be drawn. + * @param start - The starting vertex in the geometry to start drawing from. If not specified, + * drawing will start from the first vertex. + * @param instanceCount - The number of instances of the set of elements to execute. If not specified, + * all instances will be drawn. + */ + draw(topology, size, start, instanceCount) { + const { gl } = this._renderer; + const geometry = this._activeGeometry; + const glTopology = topologyToGlMap[geometry.topology || topology]; + instanceCount || (instanceCount = geometry.instanceCount); + if (geometry.indexBuffer) { + const byteSize = geometry.indexBuffer.data.BYTES_PER_ELEMENT; + const glType = byteSize === 2 ? gl.UNSIGNED_SHORT : gl.UNSIGNED_INT; + if (instanceCount > 1) { + gl.drawElementsInstanced(glTopology, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize, instanceCount); + } else { + gl.drawElements(glTopology, size || geometry.indexBuffer.data.length, glType, (start || 0) * byteSize); + } + } else if (instanceCount > 1) { + gl.drawArraysInstanced(glTopology, start || 0, size || geometry.getSize(), instanceCount); + } else { + gl.drawArrays(glTopology, start || 0, size || geometry.getSize()); + } + return this; + } + /** Unbind/reset everything. */ + unbind() { + this.gl.bindVertexArray(null); + this._activeVao = null; + this._activeGeometry = null; + } + destroy() { + this._renderer = null; + this.gl = null; + this._activeVao = null; + this._activeGeometry = null; + } + } + /** @ignore */ + GlGeometrySystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "geometry" + }; + + "use strict"; + var __defProp$i = Object.defineProperty; + var __getOwnPropSymbols$i = Object.getOwnPropertySymbols; + var __hasOwnProp$i = Object.prototype.hasOwnProperty; + var __propIsEnum$i = Object.prototype.propertyIsEnumerable; + var __defNormalProp$i = (obj, key, value) => key in obj ? __defProp$i(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$i = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$i.call(b, prop)) + __defNormalProp$i(a, prop, b[prop]); + if (__getOwnPropSymbols$i) + for (var prop of __getOwnPropSymbols$i(b)) { + if (__propIsEnum$i.call(b, prop)) + __defNormalProp$i(a, prop, b[prop]); + } + return a; + }; + const bigTriangleGeometry = new Geometry({ + attributes: { + aPosition: [ + -1, + -1, + // Bottom left corner + 3, + -1, + // Bottom right corner, extending beyond right edge + -1, + 3 + // Top left corner, extending beyond top edge + ] + } + }); + const _GlBackBufferSystem = class _GlBackBufferSystem { + constructor(renderer) { + /** if true, the back buffer is used */ + this.useBackBuffer = false; + this._useBackBufferThisRender = false; + this._renderer = renderer; + } + init(options = {}) { + const { useBackBuffer, antialias } = __spreadValues$i(__spreadValues$i({}, _GlBackBufferSystem.defaultOptions), options); + this.useBackBuffer = useBackBuffer; + this._antialias = antialias; + if (!this._renderer.context.supports.msaa) { + warn("antialiasing, is not supported on when using the back buffer"); + this._antialias = false; + } + this._state = State.for2d(); + const bigTriangleProgram = new GlProgram({ + vertex: ` + attribute vec2 aPosition; + out vec2 vUv; + + void main() { + gl_Position = vec4(aPosition, 0.0, 1.0); + + vUv = (aPosition + 1.0) / 2.0; + + // flip dem UVs + vUv.y = 1.0 - vUv.y; + }`, + fragment: ` + in vec2 vUv; + out vec4 finalColor; + + uniform sampler2D uTexture; + + void main() { + finalColor = texture(uTexture, vUv); + }`, + name: "big-triangle" + }); + this._bigTriangleShader = new Shader({ + glProgram: bigTriangleProgram, + resources: { + uTexture: Texture.WHITE.source + } + }); + } + /** + * This is called before the RenderTargetSystem is started. This is where + * we replace the target with the back buffer if required. + * @param options - The options for this render. + */ + renderStart(options) { + const renderTarget = this._renderer.renderTarget.getRenderTarget(options.target); + this._useBackBufferThisRender = this.useBackBuffer && !!renderTarget.isRoot; + if (this._useBackBufferThisRender) { + const renderTarget2 = this._renderer.renderTarget.getRenderTarget(options.target); + this._targetTexture = renderTarget2.colorTexture; + options.target = this._getBackBufferTexture(renderTarget2.colorTexture); + } + } + renderEnd() { + this._presentBackBuffer(); + } + _presentBackBuffer() { + const renderer = this._renderer; + renderer.renderTarget.finishRenderPass(); + if (!this._useBackBufferThisRender) + return; + renderer.renderTarget.bind(this._targetTexture, false); + this._bigTriangleShader.resources.uTexture = this._backBufferTexture.source; + renderer.encoder.draw({ + geometry: bigTriangleGeometry, + shader: this._bigTriangleShader, + state: this._state + }); + } + _getBackBufferTexture(targetSourceTexture) { + this._backBufferTexture = this._backBufferTexture || new Texture({ + source: new TextureSource({ + width: targetSourceTexture.width, + height: targetSourceTexture.height, + resolution: targetSourceTexture._resolution, + antialias: this._antialias + }) + }); + this._backBufferTexture.source.resize( + targetSourceTexture.width, + targetSourceTexture.height, + targetSourceTexture._resolution + ); + return this._backBufferTexture; + } + /** destroys the back buffer */ + destroy() { + if (this._backBufferTexture) { + this._backBufferTexture.destroy(); + this._backBufferTexture = null; + } + } + }; + /** @ignore */ + _GlBackBufferSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "backBuffer", + priority: 1 + }; + /** default options for the back buffer system */ + _GlBackBufferSystem.defaultOptions = { + /** if true will use the back buffer where required */ + useBackBuffer: false + }; + let GlBackBufferSystem = _GlBackBufferSystem; + + "use strict"; + class GlColorMaskSystem { + constructor(renderer) { + this._colorMaskCache = 15; + this._renderer = renderer; + } + setMask(colorMask) { + if (this._colorMaskCache === colorMask) + return; + this._colorMaskCache = colorMask; + this._renderer.gl.colorMask( + !!(colorMask & 8), + !!(colorMask & 4), + !!(colorMask & 2), + !!(colorMask & 1) + ); + } + } + /** @ignore */ + GlColorMaskSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "colorMask" + }; + + "use strict"; + class GlEncoderSystem { + constructor(renderer) { + this.commandFinished = Promise.resolve(); + this._renderer = renderer; + } + setGeometry(geometry, shader) { + this._renderer.geometry.bind(geometry, shader.glProgram); + } + finishRenderPass() { + } + draw(options) { + const renderer = this._renderer; + const { geometry, shader, state, skipSync, topology: type, size, start, instanceCount } = options; + renderer.shader.bind(shader, skipSync); + renderer.geometry.bind(geometry, renderer.shader._activeProgram); + if (state) { + renderer.state.set(state); + } + renderer.geometry.draw(type, size, start, instanceCount != null ? instanceCount : geometry.instanceCount); + } + destroy() { + this._renderer = null; + } + } + /** @ignore */ + GlEncoderSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "encoder" + }; + + "use strict"; + class GlRenderTarget { + constructor() { + this.width = -1; + this.height = -1; + this.msaa = false; + this.msaaRenderBuffer = []; + } + } + + "use strict"; + const GpuStencilModesToPixi = []; + GpuStencilModesToPixi[STENCIL_MODES.NONE] = void 0; + GpuStencilModesToPixi[STENCIL_MODES.DISABLED] = { + stencilWriteMask: 0, + stencilReadMask: 0 + }; + GpuStencilModesToPixi[STENCIL_MODES.RENDERING_MASK_ADD] = { + stencilFront: { + compare: "equal", + passOp: "increment-clamp" + }, + stencilBack: { + compare: "equal", + passOp: "increment-clamp" + } + }; + GpuStencilModesToPixi[STENCIL_MODES.RENDERING_MASK_REMOVE] = { + stencilFront: { + compare: "equal", + passOp: "decrement-clamp" + }, + stencilBack: { + compare: "equal", + passOp: "decrement-clamp" + } + }; + GpuStencilModesToPixi[STENCIL_MODES.MASK_ACTIVE] = { + stencilWriteMask: 0, + stencilFront: { + compare: "equal", + passOp: "keep" + }, + stencilBack: { + compare: "equal", + passOp: "keep" + } + }; + + "use strict"; + class GlStencilSystem { + constructor(renderer) { + this._stencilCache = { + enabled: false, + stencilReference: 0, + stencilMode: STENCIL_MODES.NONE + }; + this._renderTargetStencilState = /* @__PURE__ */ Object.create(null); + renderer.renderTarget.onRenderTargetChange.add(this); + } + contextChange(gl) { + this._gl = gl; + this._comparisonFuncMapping = { + always: gl.ALWAYS, + never: gl.NEVER, + equal: gl.EQUAL, + "not-equal": gl.NOTEQUAL, + less: gl.LESS, + "less-equal": gl.LEQUAL, + greater: gl.GREATER, + "greater-equal": gl.GEQUAL + }; + this._stencilOpsMapping = { + keep: gl.KEEP, + zero: gl.ZERO, + replace: gl.REPLACE, + invert: gl.INVERT, + "increment-clamp": gl.INCR, + "decrement-clamp": gl.DECR, + "increment-wrap": gl.INCR_WRAP, + "decrement-wrap": gl.DECR_WRAP + }; + this._stencilCache.enabled = false; + this._stencilCache.stencilMode = STENCIL_MODES.NONE; + this._stencilCache.stencilReference = 0; + } + onRenderTargetChange(renderTarget) { + if (this._activeRenderTarget === renderTarget) + return; + this._activeRenderTarget = renderTarget; + let stencilState = this._renderTargetStencilState[renderTarget.uid]; + if (!stencilState) { + stencilState = this._renderTargetStencilState[renderTarget.uid] = { + stencilMode: STENCIL_MODES.DISABLED, + stencilReference: 0 + }; + } + this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference); + } + setStencilMode(stencilMode, stencilReference) { + const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid]; + const gl = this._gl; + const mode = GpuStencilModesToPixi[stencilMode]; + const _stencilCache = this._stencilCache; + stencilState.stencilMode = stencilMode; + stencilState.stencilReference = stencilReference; + if (stencilMode === STENCIL_MODES.DISABLED) { + if (this._stencilCache.enabled) { + this._stencilCache.enabled = false; + gl.disable(gl.STENCIL_TEST); + } + return; + } + if (!this._stencilCache.enabled) { + this._stencilCache.enabled = true; + gl.enable(gl.STENCIL_TEST); + } + if (stencilMode !== _stencilCache.stencilMode || _stencilCache.stencilReference !== stencilReference) { + _stencilCache.stencilMode = stencilMode; + _stencilCache.stencilReference = stencilReference; + gl.stencilFunc(this._comparisonFuncMapping[mode.stencilBack.compare], stencilReference, 255); + gl.stencilOp(gl.KEEP, gl.KEEP, this._stencilOpsMapping[mode.stencilBack.passOp]); + } + } + } + /** @ignore */ + GlStencilSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "stencil" + }; + + "use strict"; + class UboSystem { + constructor(adaptor) { + /** Cache of uniform buffer layouts and sync functions, so we don't have to re-create them */ + this._syncFunctionHash = /* @__PURE__ */ Object.create(null); + this._adaptor = adaptor; + this._systemCheck(); + } + /** + * Overrideable function by `pixi.js/unsafe-eval` to silence + * throwing an error if platform doesn't support unsafe-evals. + * @private + */ + _systemCheck() { + if (!unsafeEvalSupported()) { + throw new Error("Current environment does not allow unsafe-eval, please use pixi.js/unsafe-eval module to enable support."); + } + } + ensureUniformGroup(uniformGroup) { + const uniformData = this.getUniformGroupData(uniformGroup); + uniformGroup.buffer || (uniformGroup.buffer = new Buffer({ + data: new Float32Array(uniformData.layout.size / 4), + usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST + })); + } + getUniformGroupData(uniformGroup) { + return this._syncFunctionHash[uniformGroup._signature] || this._initUniformGroup(uniformGroup); + } + _initUniformGroup(uniformGroup) { + const uniformGroupSignature = uniformGroup._signature; + let uniformData = this._syncFunctionHash[uniformGroupSignature]; + if (!uniformData) { + const elements = Object.keys(uniformGroup.uniformStructures).map((i) => uniformGroup.uniformStructures[i]); + const layout = this._adaptor.createUboElements(elements); + const syncFunction = this._generateUboSync(layout.uboElements); + uniformData = this._syncFunctionHash[uniformGroupSignature] = { + layout, + syncFunction + }; + } + return this._syncFunctionHash[uniformGroupSignature]; + } + _generateUboSync(uboElements) { + return this._adaptor.generateUboSync(uboElements); + } + syncUniformGroup(uniformGroup, data, offset) { + const uniformGroupData = this.getUniformGroupData(uniformGroup); + uniformGroup.buffer || (uniformGroup.buffer = new Buffer({ + data: new Float32Array(uniformGroupData.layout.size / 4), + usage: BufferUsage.UNIFORM | BufferUsage.COPY_DST + })); + data || (data = uniformGroup.buffer.data); + offset || (offset = 0); + uniformGroupData.syncFunction(uniformGroup.uniforms, data, offset); + return true; + } + updateUniformGroup(uniformGroup) { + if (uniformGroup.isStatic && !uniformGroup._dirtyId) + return false; + uniformGroup._dirtyId = 0; + const synced = this.syncUniformGroup(uniformGroup); + uniformGroup.buffer.update(); + return synced; + } + destroy() { + this._syncFunctionHash = null; + } + } + + "use strict"; + const WGSL_TO_STD40_SIZE = { + f32: 4, + "vec2": 8, + "vec3": 12, + "vec4": 16, + "mat2x2": 16 * 2, + "mat3x3": 16 * 3, + "mat4x4": 16 * 4 + // TODO - not essential for now but support these in the future + // int: 4, + // ivec2: 8, + // ivec3: 12, + // ivec4: 16, + // uint: 4, + // uvec2: 8, + // uvec3: 12, + // uvec4: 16, + // bool: 4, + // bvec2: 8, + // bvec3: 12, + // bvec4: 16, + // mat2: 16 * 2, + // mat3: 16 * 3, + // mat4: 16 * 4, + }; + function createUboElementsSTD40(uniformData) { + const uboElements = uniformData.map((data) => ({ + data, + offset: 0, + size: 0 + })); + let size = 0; + let chunkSize = 0; + let offset = 0; + for (let i = 0; i < uboElements.length; i++) { + const uboElement = uboElements[i]; + size = WGSL_TO_STD40_SIZE[uboElement.data.type]; + if (!size) { + throw new Error(`Unknown type ${uboElement.data.type}`); + } + if (uboElement.data.size > 1) { + size = Math.max(size, 16) * uboElement.data.size; + } + uboElement.size = size; + if (chunkSize % size !== 0 && chunkSize < 16) { + const lineUpValue = chunkSize % size % 16; + chunkSize += lineUpValue; + offset += lineUpValue; + } + if (chunkSize + size > 16) { + offset = Math.ceil(offset / 16) * 16; + uboElement.offset = offset; + offset += size; + chunkSize = size; + } else { + uboElement.offset = offset; + chunkSize += size; + offset += size; + } + } + offset = Math.ceil(offset / 16) * 16; + return { uboElements, size: offset }; + } + + "use strict"; + const uniformParsers = [ + // uploading pixi matrix object to mat3 + { + type: "mat3x3", + test: (data) => { + const value = data.value; + return value.a !== void 0; + }, + ubo: ` + var matrix = uv[name].toArray(true); + data[offset] = matrix[0]; + data[offset + 1] = matrix[1]; + data[offset + 2] = matrix[2]; + data[offset + 4] = matrix[3]; + data[offset + 5] = matrix[4]; + data[offset + 6] = matrix[5]; + data[offset + 8] = matrix[6]; + data[offset + 9] = matrix[7]; + data[offset + 10] = matrix[8]; + `, + uniform: ` + gl.uniformMatrix3fv(ud[name].location, false, uv[name].toArray(true)); + ` + }, + // uploading a pixi rectangle as a vec4 + { + type: "vec4", + test: (data) => data.type === "vec4" && data.size === 1 && data.value.width !== void 0, + ubo: ` + v = uv[name]; + data[offset] = v.x; + data[offset + 1] = v.y; + data[offset + 2] = v.width; + data[offset + 3] = v.height; + `, + uniform: ` + cv = ud[name].value; + v = uv[name]; + if (cv[0] !== v.x || cv[1] !== v.y || cv[2] !== v.width || cv[3] !== v.height) { + cv[0] = v.x; + cv[1] = v.y; + cv[2] = v.width; + cv[3] = v.height; + gl.uniform4f(ud[name].location, v.x, v.y, v.width, v.height); + } + ` + }, + // uploading a pixi point as a vec2 + { + type: "vec2", + test: (data) => data.type === "vec2" && data.size === 1 && data.value.x !== void 0, + ubo: ` + v = uv[name]; + data[offset] = v.x; + data[offset + 1] = v.y; + `, + uniform: ` + cv = ud[name].value; + v = uv[name]; + if (cv[0] !== v.x || cv[1] !== v.y) { + cv[0] = v.x; + cv[1] = v.y; + gl.uniform2f(ud[name].location, v.x, v.y); + } + ` + }, + // uploading a pixi color as a vec4 + { + type: "vec4", + test: (data) => data.type === "vec4" && data.size === 1 && data.value.red !== void 0, + ubo: ` + v = uv[name]; + data[offset] = v.red; + data[offset + 1] = v.green; + data[offset + 2] = v.blue; + data[offset + 3] = v.alpha; + `, + uniform: ` + cv = ud[name].value; + v = uv[name]; + if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue || cv[3] !== v.alpha) { + cv[0] = v.red; + cv[1] = v.green; + cv[2] = v.blue; + cv[3] = v.alpha; + gl.uniform4f(ud[name].location, v.red, v.green, v.blue, v.alpha); + } + ` + }, + // uploading a pixi color as a vec3 + { + type: "vec3", + test: (data) => data.type === "vec3" && data.size === 1 && data.value.red !== void 0, + ubo: ` + v = uv[name]; + data[offset] = v.red; + data[offset + 1] = v.green; + data[offset + 2] = v.blue; + `, + uniform: ` + cv = ud[name].value; + v = uv[name]; + if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue) { + cv[0] = v.red; + cv[1] = v.green; + cv[2] = v.blue; + gl.uniform3f(ud[name].location, v.red, v.green, v.blue); + } + ` + } + ]; + + "use strict"; + function createUboSyncFunction(uboElements, parserCode, arrayGenerationFunction, singleSettersMap) { + const funcFragments = [` + var v = null; + var v2 = null; + var t = 0; + var index = 0; + var name = null; + var arrayOffset = null; + `]; + let prev = 0; + for (let i = 0; i < uboElements.length; i++) { + const uboElement = uboElements[i]; + const name = uboElement.data.name; + let parsed = false; + let offset = 0; + for (let j = 0; j < uniformParsers.length; j++) { + const uniformParser = uniformParsers[j]; + if (uniformParser.test(uboElement.data)) { + offset = uboElement.offset / 4; + funcFragments.push( + `name = "${name}";`, + `offset += ${offset - prev};`, + uniformParsers[j][parserCode] || uniformParsers[j].ubo + ); + parsed = true; + break; + } + } + if (!parsed) { + if (uboElement.data.size > 1) { + offset = uboElement.offset / 4; + funcFragments.push(arrayGenerationFunction(uboElement, offset - prev)); + } else { + const template = singleSettersMap[uboElement.data.type]; + offset = uboElement.offset / 4; + funcFragments.push( + /* wgsl */ + ` + v = uv.${name}; + offset += ${offset - prev}; + ${template}; + ` + ); + } + } + prev = offset; + } + const fragmentSrc = funcFragments.join("\n"); + return new Function( + "uv", + "data", + "offset", + fragmentSrc + ); + } + + "use strict"; + var __defProp$h = Object.defineProperty; + var __defProps$7 = Object.defineProperties; + var __getOwnPropDescs$7 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$h = Object.getOwnPropertySymbols; + var __hasOwnProp$h = Object.prototype.hasOwnProperty; + var __propIsEnum$h = Object.prototype.propertyIsEnumerable; + var __defNormalProp$h = (obj, key, value) => key in obj ? __defProp$h(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$h = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$h.call(b, prop)) + __defNormalProp$h(a, prop, b[prop]); + if (__getOwnPropSymbols$h) + for (var prop of __getOwnPropSymbols$h(b)) { + if (__propIsEnum$h.call(b, prop)) + __defNormalProp$h(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$7 = (a, b) => __defProps$7(a, __getOwnPropDescs$7(b)); + function loopMatrix(col, row) { + const total = col * row; + return ` + for (let i = 0; i < ${total}; i++) { + data[offset + (((i / ${col})|0) * 4) + (i % ${col})] = v[i]; + } + `; + } + const uboSyncFunctionsSTD40 = { + f32: ` + data[offset] = v;`, + i32: ` + data[offset] = v;`, + "vec2": ` + data[offset] = v[0]; + data[offset + 1] = v[1];`, + "vec3": ` + data[offset] = v[0]; + data[offset + 1] = v[1]; + data[offset + 2] = v[2];`, + "vec4": ` + data[offset] = v[0]; + data[offset + 1] = v[1]; + data[offset + 2] = v[2]; + data[offset + 3] = v[3];`, + "mat2x2": ` + data[offset] = v[0]; + data[offset + 1] = v[1]; + data[offset + 4] = v[2]; + data[offset + 5] = v[3];`, + "mat3x3": ` + data[offset] = v[0]; + data[offset + 1] = v[1]; + data[offset + 2] = v[2]; + data[offset + 4] = v[3]; + data[offset + 5] = v[4]; + data[offset + 6] = v[5]; + data[offset + 8] = v[6]; + data[offset + 9] = v[7]; + data[offset + 10] = v[8];`, + "mat4x4": ` + for (let i = 0; i < 16; i++) { + data[offset + i] = v[i]; + }`, + "mat3x2": loopMatrix(3, 2), + "mat4x2": loopMatrix(4, 2), + "mat2x3": loopMatrix(2, 3), + "mat4x3": loopMatrix(4, 3), + "mat2x4": loopMatrix(2, 4), + "mat3x4": loopMatrix(3, 4) + }; + const uboSyncFunctionsWGSL = __spreadProps$7(__spreadValues$h({}, uboSyncFunctionsSTD40), { + "mat2x2": ` + data[offset] = v[0]; + data[offset + 1] = v[1]; + data[offset + 2] = v[2]; + data[offset + 3] = v[3]; + ` + }); + + "use strict"; + function generateArraySyncSTD40(uboElement, offsetToAdd) { + const rowSize = Math.max(WGSL_TO_STD40_SIZE[uboElement.data.type] / 16, 1); + const elementSize = uboElement.data.value.length / uboElement.data.size; + const remainder = (4 - elementSize % 4) % 4; + return ` + v = uv.${uboElement.data.name}; + offset += ${offsetToAdd}; + + arrayOffset = offset; + + t = 0; + + for(var i=0; i < ${uboElement.data.size * rowSize}; i++) + { + for(var j = 0; j < ${elementSize}; j++) + { + data[arrayOffset++] = v[t++]; + } + ${remainder !== 0 ? `arrayOffset += ${remainder};` : ""} + } + `; + } + + "use strict"; + function createUboSyncFunctionSTD40(uboElements) { + return createUboSyncFunction( + uboElements, + "uboStd40", + generateArraySyncSTD40, + uboSyncFunctionsSTD40 + ); + } + + "use strict"; + class GlUboSystem extends UboSystem { + constructor() { + super({ + createUboElements: createUboElementsSTD40, + generateUboSync: createUboSyncFunctionSTD40 + }); + } + } + /** @ignore */ + GlUboSystem.extension = { + type: [ExtensionType.WebGLSystem], + name: "ubo" + }; + + "use strict"; + class GlRenderTargetAdaptor { + constructor() { + this._clearColorCache = [0, 0, 0, 0]; + this._viewPortCache = new Rectangle(); + } + init(renderer, renderTargetSystem) { + this._renderer = renderer; + this._renderTargetSystem = renderTargetSystem; + renderer.runners.contextChange.add(this); + } + contextChange() { + this._clearColorCache = [0, 0, 0, 0]; + this._viewPortCache = new Rectangle(); + } + copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) { + const renderTargetSystem = this._renderTargetSystem; + const renderer = this._renderer; + const glRenderTarget = renderTargetSystem.getGpuRenderTarget(sourceRenderSurfaceTexture); + const gl = renderer.gl; + this.finishRenderPass(sourceRenderSurfaceTexture); + gl.bindFramebuffer(gl.FRAMEBUFFER, glRenderTarget.resolveTargetFramebuffer); + renderer.texture.bind(destinationTexture, 0); + gl.copyTexSubImage2D( + gl.TEXTURE_2D, + 0, + originDest.x, + originDest.y, + originSrc.x, + originSrc.y, + size.width, + size.height + ); + return destinationTexture; + } + startRenderPass(renderTarget, clear = true, clearColor, viewport) { + const renderTargetSystem = this._renderTargetSystem; + const source = renderTarget.colorTexture; + const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget); + let viewPortY = viewport.y; + if (renderTarget.isRoot) { + viewPortY = source.pixelHeight - viewport.height; + } + renderTarget.colorTextures.forEach((texture) => { + this._renderer.texture.unbind(texture); + }); + const gl = this._renderer.gl; + gl.bindFramebuffer(gl.FRAMEBUFFER, gpuRenderTarget.framebuffer); + const viewPortCache = this._viewPortCache; + if (viewPortCache.x !== viewport.x || viewPortCache.y !== viewPortY || viewPortCache.width !== viewport.width || viewPortCache.height !== viewport.height) { + viewPortCache.x = viewport.x; + viewPortCache.y = viewPortY; + viewPortCache.width = viewport.width; + viewPortCache.height = viewport.height; + gl.viewport( + viewport.x, + viewPortY, + viewport.width, + viewport.height + ); + } + if (!gpuRenderTarget.depthStencilRenderBuffer && (renderTarget.stencil || renderTarget.depth)) { + this._initStencil(gpuRenderTarget); + } + this.clear(renderTarget, clear, clearColor); + } + finishRenderPass(renderTarget) { + const renderTargetSystem = this._renderTargetSystem; + const glRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget); + if (!glRenderTarget.msaa) + return; + const gl = this._renderer.gl; + gl.bindFramebuffer(gl.FRAMEBUFFER, glRenderTarget.resolveTargetFramebuffer); + gl.bindFramebuffer(gl.READ_FRAMEBUFFER, glRenderTarget.framebuffer); + gl.blitFramebuffer( + 0, + 0, + glRenderTarget.width, + glRenderTarget.height, + 0, + 0, + glRenderTarget.width, + glRenderTarget.height, + gl.COLOR_BUFFER_BIT, + gl.NEAREST + ); + gl.bindFramebuffer(gl.FRAMEBUFFER, glRenderTarget.framebuffer); + } + initGpuRenderTarget(renderTarget) { + const renderer = this._renderer; + const gl = renderer.gl; + const glRenderTarget = new GlRenderTarget(); + if (renderTarget.colorTexture.resource === renderer.gl.canvas) { + glRenderTarget.framebuffer = null; + return glRenderTarget; + } + this._initColor(renderTarget, glRenderTarget); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + return glRenderTarget; + } + destroyGpuRenderTarget(gpuRenderTarget) { + const gl = this._renderer.gl; + if (gpuRenderTarget.framebuffer) { + gl.deleteFramebuffer(gpuRenderTarget.framebuffer); + gpuRenderTarget.framebuffer = null; + } + if (gpuRenderTarget.resolveTargetFramebuffer) { + gl.deleteFramebuffer(gpuRenderTarget.resolveTargetFramebuffer); + gpuRenderTarget.resolveTargetFramebuffer = null; + } + if (gpuRenderTarget.depthStencilRenderBuffer) { + gl.deleteRenderbuffer(gpuRenderTarget.depthStencilRenderBuffer); + gpuRenderTarget.depthStencilRenderBuffer = null; + } + gpuRenderTarget.msaaRenderBuffer.forEach((renderBuffer) => { + gl.deleteRenderbuffer(renderBuffer); + }); + gpuRenderTarget.msaaRenderBuffer = null; + } + clear(_renderTarget, clear, clearColor) { + if (!clear) + return; + const renderTargetSystem = this._renderTargetSystem; + if (typeof clear === "boolean") { + clear = clear ? CLEAR.ALL : CLEAR.NONE; + } + const gl = this._renderer.gl; + if (clear & CLEAR.COLOR) { + clearColor != null ? clearColor : clearColor = renderTargetSystem.defaultClearColor; + const clearColorCache = this._clearColorCache; + const clearColorArray = clearColor; + if (clearColorCache[0] !== clearColorArray[0] || clearColorCache[1] !== clearColorArray[1] || clearColorCache[2] !== clearColorArray[2] || clearColorCache[3] !== clearColorArray[3]) { + clearColorCache[0] = clearColorArray[0]; + clearColorCache[1] = clearColorArray[1]; + clearColorCache[2] = clearColorArray[2]; + clearColorCache[3] = clearColorArray[3]; + gl.clearColor(clearColorArray[0], clearColorArray[1], clearColorArray[2], clearColorArray[3]); + } + } + gl.clear(clear); + } + resizeGpuRenderTarget(renderTarget) { + if (renderTarget.isRoot) + return; + const renderTargetSystem = this._renderTargetSystem; + const glRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget); + this._resizeColor(renderTarget, glRenderTarget); + if (renderTarget.stencil) { + this._resizeStencil(glRenderTarget); + } + } + _initColor(renderTarget, glRenderTarget) { + const renderer = this._renderer; + const gl = renderer.gl; + const resolveTargetFramebuffer = gl.createFramebuffer(); + glRenderTarget.resolveTargetFramebuffer = resolveTargetFramebuffer; + gl.bindFramebuffer(gl.FRAMEBUFFER, resolveTargetFramebuffer); + glRenderTarget.width = renderTarget.colorTexture.source.pixelWidth; + glRenderTarget.height = renderTarget.colorTexture.source.pixelHeight; + renderTarget.colorTextures.forEach((colorTexture, i) => { + const source = colorTexture.source; + if (source.antialias) { + if (renderer.context.supports.msaa) { + glRenderTarget.msaa = true; + } else { + warn("[RenderTexture] Antialiasing on textures is not supported in WebGL1"); + } + } + renderer.texture.bindSource(source, 0); + const glSource = renderer.texture.getGlSource(source); + const glTexture = glSource.texture; + gl.framebufferTexture2D( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0 + i, + 3553, + // texture.target, + glTexture, + 0 + ); + }); + if (glRenderTarget.msaa) { + const viewFramebuffer = gl.createFramebuffer(); + glRenderTarget.framebuffer = viewFramebuffer; + gl.bindFramebuffer(gl.FRAMEBUFFER, viewFramebuffer); + renderTarget.colorTextures.forEach((_, i) => { + const msaaRenderBuffer = gl.createRenderbuffer(); + glRenderTarget.msaaRenderBuffer[i] = msaaRenderBuffer; + }); + } else { + glRenderTarget.framebuffer = resolveTargetFramebuffer; + } + this._resizeColor(renderTarget, glRenderTarget); + } + _resizeColor(renderTarget, glRenderTarget) { + const source = renderTarget.colorTexture.source; + glRenderTarget.width = source.pixelWidth; + glRenderTarget.height = source.pixelHeight; + renderTarget.colorTextures.forEach((colorTexture, i) => { + if (i === 0) + return; + colorTexture.source.resize(source.width, source.height, source._resolution); + }); + if (glRenderTarget.msaa) { + const renderer = this._renderer; + const gl = renderer.gl; + const viewFramebuffer = glRenderTarget.framebuffer; + gl.bindFramebuffer(gl.FRAMEBUFFER, viewFramebuffer); + renderTarget.colorTextures.forEach((colorTexture, i) => { + const source2 = colorTexture.source; + renderer.texture.bindSource(source2, 0); + const glSource = renderer.texture.getGlSource(source2); + const glInternalFormat = glSource.internalFormat; + const msaaRenderBuffer = glRenderTarget.msaaRenderBuffer[i]; + gl.bindRenderbuffer( + gl.RENDERBUFFER, + msaaRenderBuffer + ); + gl.renderbufferStorageMultisample( + gl.RENDERBUFFER, + 4, + glInternalFormat, + source2.pixelWidth, + source2.pixelHeight + ); + gl.framebufferRenderbuffer( + gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0 + i, + gl.RENDERBUFFER, + msaaRenderBuffer + ); + }); + } + } + _initStencil(glRenderTarget) { + if (glRenderTarget.framebuffer === null) + return; + const gl = this._renderer.gl; + const depthStencilRenderBuffer = gl.createRenderbuffer(); + glRenderTarget.depthStencilRenderBuffer = depthStencilRenderBuffer; + gl.bindRenderbuffer( + gl.RENDERBUFFER, + depthStencilRenderBuffer + ); + gl.framebufferRenderbuffer( + gl.FRAMEBUFFER, + gl.DEPTH_STENCIL_ATTACHMENT, + gl.RENDERBUFFER, + depthStencilRenderBuffer + ); + this._resizeStencil(glRenderTarget); + } + _resizeStencil(glRenderTarget) { + const gl = this._renderer.gl; + gl.bindRenderbuffer( + gl.RENDERBUFFER, + glRenderTarget.depthStencilRenderBuffer + ); + if (glRenderTarget.msaa) { + gl.renderbufferStorageMultisample( + gl.RENDERBUFFER, + 4, + gl.DEPTH24_STENCIL8, + glRenderTarget.width, + glRenderTarget.height + ); + } else { + gl.renderbufferStorage( + gl.RENDERBUFFER, + this._renderer.context.webGLVersion === 2 ? gl.DEPTH24_STENCIL8 : gl.DEPTH_STENCIL, + glRenderTarget.width, + glRenderTarget.height + ); + } + } + } + + "use strict"; + function calculateProjection(pm, x, y, width, height, flipY) { + const sign = flipY ? 1 : -1; + pm.identity(); + pm.a = 1 / width * 2; + pm.d = sign * (1 / height * 2); + pm.tx = -1 - x * pm.a; + pm.ty = -sign - y * pm.d; + return pm; + } + + "use strict"; + var __defProp$g = Object.defineProperty; + var __getOwnPropSymbols$g = Object.getOwnPropertySymbols; + var __hasOwnProp$g = Object.prototype.hasOwnProperty; + var __propIsEnum$g = Object.prototype.propertyIsEnumerable; + var __defNormalProp$g = (obj, key, value) => key in obj ? __defProp$g(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$g = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$g.call(b, prop)) + __defNormalProp$g(a, prop, b[prop]); + if (__getOwnPropSymbols$g) + for (var prop of __getOwnPropSymbols$g(b)) { + if (__propIsEnum$g.call(b, prop)) + __defNormalProp$g(a, prop, b[prop]); + } + return a; + }; + const canvasCache = /* @__PURE__ */ new Map(); + function getCanvasTexture(canvas, options) { + if (!canvasCache.has(canvas)) { + const texture = new Texture({ + source: new CanvasSource(__spreadValues$g({ + resource: canvas + }, options)) + }); + const onDestroy = () => { + if (canvasCache.get(canvas) === texture) { + canvasCache.delete(canvas); + } + }; + texture.once("destroy", onDestroy); + texture.source.once("destroy", onDestroy); + canvasCache.set(canvas, texture); + } + return canvasCache.get(canvas); + } + function hasCachedCanvasTexture(canvas) { + return canvasCache.has(canvas); + } + + "use strict"; + function isRenderingToScreen(renderTarget) { + const resource = renderTarget.colorTexture.source.resource; + return globalThis.HTMLCanvasElement && resource instanceof HTMLCanvasElement && document.body.contains(resource); + } + + "use strict"; + var __defProp$f = Object.defineProperty; + var __getOwnPropSymbols$f = Object.getOwnPropertySymbols; + var __hasOwnProp$f = Object.prototype.hasOwnProperty; + var __propIsEnum$f = Object.prototype.propertyIsEnumerable; + var __defNormalProp$f = (obj, key, value) => key in obj ? __defProp$f(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$f = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$f.call(b, prop)) + __defNormalProp$f(a, prop, b[prop]); + if (__getOwnPropSymbols$f) + for (var prop of __getOwnPropSymbols$f(b)) { + if (__propIsEnum$f.call(b, prop)) + __defNormalProp$f(a, prop, b[prop]); + } + return a; + }; + const _RenderTarget = class _RenderTarget { + /** + * @param [descriptor] - Options for creating a render target. + */ + constructor(descriptor = {}) { + this.uid = uid("renderTarget"); + /** + * An array of textures that can be written to by the GPU - mostly this has one texture in Pixi, but you could + * write to multiple if required! (eg deferred lighting) + */ + this.colorTextures = []; + this.dirtyId = 0; + this.isRoot = false; + this._size = new Float32Array(2); + /** if true, then when the render target is destroyed, it will destroy all the textures that were created for it. */ + this._managedColorTextures = false; + descriptor = __spreadValues$f(__spreadValues$f({}, _RenderTarget.defaultOptions), descriptor); + this.stencil = descriptor.stencil; + this.depth = descriptor.depth; + this.isRoot = descriptor.isRoot; + if (typeof descriptor.colorTextures === "number") { + this._managedColorTextures = true; + for (let i = 0; i < descriptor.colorTextures; i++) { + this.colorTextures.push( + new TextureSource({ + width: descriptor.width, + height: descriptor.height, + resolution: descriptor.resolution, + antialias: descriptor.antialias + }) + ); + } + } else { + this.colorTextures = [...descriptor.colorTextures.map((texture) => texture.source)]; + const colorSource = this.colorTexture.source; + this.resize(colorSource.width, colorSource.height, colorSource._resolution); + } + this.colorTexture.source.on("resize", this.onSourceResize, this); + if (descriptor.depthStencilTexture || this.stencil) { + if (descriptor.depthStencilTexture instanceof Texture || descriptor.depthStencilTexture instanceof TextureSource) { + this.depthStencilTexture = descriptor.depthStencilTexture.source; + } else { + this.ensureDepthStencilTexture(); + } + } + } + get size() { + const _size = this._size; + _size[0] = this.pixelWidth; + _size[1] = this.pixelHeight; + return _size; + } + get width() { + return this.colorTexture.source.width; + } + get height() { + return this.colorTexture.source.height; + } + get pixelWidth() { + return this.colorTexture.source.pixelWidth; + } + get pixelHeight() { + return this.colorTexture.source.pixelHeight; + } + get resolution() { + return this.colorTexture.source._resolution; + } + get colorTexture() { + return this.colorTextures[0]; + } + onSourceResize(source) { + this.resize(source.width, source.height, source._resolution, true); + } + /** + * This will ensure a depthStencil texture is created for this render target. + * Most likely called by the mask system to make sure we have stencil buffer added. + * @internal + * @ignore + */ + ensureDepthStencilTexture() { + if (!this.depthStencilTexture) { + this.depthStencilTexture = new TextureSource({ + width: this.width, + height: this.height, + resolution: this.resolution, + format: "depth24plus-stencil8", + autoGenerateMipmaps: false, + antialias: false, + mipLevelCount: 1 + // sampleCount: handled by the render target system.. + }); + } + } + resize(width, height, resolution = this.resolution, skipColorTexture = false) { + this.dirtyId++; + this.colorTextures.forEach((colorTexture, i) => { + if (skipColorTexture && i === 0) + return; + colorTexture.source.resize(width, height, resolution); + }); + if (this.depthStencilTexture) { + this.depthStencilTexture.source.resize(width, height, resolution); + } + } + destroy() { + this.colorTexture.source.off("resize", this.onSourceResize, this); + if (this._managedColorTextures) { + this.colorTextures.forEach((texture) => { + texture.destroy(); + }); + } + if (this.depthStencilTexture) { + this.depthStencilTexture.destroy(); + delete this.depthStencilTexture; + } + } + }; + /** The default options for a render target */ + _RenderTarget.defaultOptions = { + /** the width of the RenderTarget */ + width: 0, + /** the height of the RenderTarget */ + height: 0, + /** the resolution of the RenderTarget */ + resolution: 1, + /** an array of textures, or a number indicating how many color textures there should be */ + colorTextures: 1, + /** should this render target have a stencil buffer? */ + stencil: false, + /** should this render target have a depth buffer? */ + depth: false, + /** should this render target be antialiased? */ + antialias: false, + // save on perf by default! + /** is this a root element, true if this is gl context owners render target */ + isRoot: false + }; + let RenderTarget = _RenderTarget; + + "use strict"; + class RenderTargetSystem { + constructor(renderer) { + /** This is the root viewport for the render pass*/ + this.rootViewPort = new Rectangle(); + /** the current viewport that the gpu is using */ + this.viewport = new Rectangle(); + /** + * a runner that lets systems know if the active render target has changed. + * Eg the Stencil System needs to know so it can manage the stencil buffer + */ + this.onRenderTargetChange = new SystemRunner("onRenderTargetChange"); + /** the projection matrix that is used by the shaders based on the active render target and the viewport */ + this.projectionMatrix = new Matrix(); + /** the default clear color for render targets */ + this.defaultClearColor = [0, 0, 0, 0]; + /** + * a hash that stores the render target for a given render surface. When you pass in a texture source, + * a render target is created for it. This map stores and makes it easy to retrieve the render target + */ + this._renderSurfaceToRenderTargetHash = /* @__PURE__ */ new Map(); + /** A hash that stores a gpu render target for a given render target. */ + this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null); + /** + * A stack that stores the render target and frame that is currently being rendered to. + * When push is called, the current render target is stored in this stack. + * When pop is called, the previous render target is restored. + */ + this._renderTargetStack = []; + this._renderer = renderer; + } + /** called when dev wants to finish a render pass */ + finishRenderPass() { + this.adaptor.finishRenderPass(this.renderTarget); + } + /** + * called when the renderer starts to render a scene. + * @param options + * @param options.target - the render target to render to + * @param options.clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111 + * @param options.clearColor - the color to clear to + * @param options.frame - the frame to render to + */ + renderStart({ + target, + clear, + clearColor, + frame + }) { + this._renderTargetStack.length = 0; + this.push( + target, + clear, + clearColor, + frame + ); + this.rootViewPort.copyFrom(this.viewport); + this.rootRenderTarget = this.renderTarget; + this.renderingToScreen = isRenderingToScreen(this.rootRenderTarget); + } + /** + * Binding a render surface! This is the main function of the render target system. + * It will take the RenderSurface (which can be a texture, canvas, or render target) and bind it to the renderer. + * Once bound all draw calls will be rendered to the render surface. + * + * If a frame is not provide and the render surface is a texture, the frame of the texture will be used. + * @param renderSurface - the render surface to bind + * @param clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111 + * @param clearColor - the color to clear to + * @param frame - the frame to render to + * @returns the render target that was bound + */ + bind(renderSurface, clear = true, clearColor, frame) { + const renderTarget = this.getRenderTarget(renderSurface); + const didChange = this.renderTarget !== renderTarget; + this.renderTarget = renderTarget; + this.renderSurface = renderSurface; + const gpuRenderTarget = this.getGpuRenderTarget(renderTarget); + if (renderTarget.pixelWidth !== gpuRenderTarget.width || renderTarget.pixelHeight !== gpuRenderTarget.height) { + this.adaptor.resizeGpuRenderTarget(renderTarget); + gpuRenderTarget.width = renderTarget.pixelWidth; + gpuRenderTarget.height = renderTarget.pixelHeight; + } + const source = renderTarget.colorTexture; + const viewport = this.viewport; + const pixelWidth = source.pixelWidth; + const pixelHeight = source.pixelHeight; + if (!frame && renderSurface instanceof Texture) { + frame = renderSurface.frame; + } + if (frame) { + const resolution = source._resolution; + viewport.x = frame.x * resolution + 0.5 | 0; + viewport.y = frame.y * resolution + 0.5 | 0; + viewport.width = frame.width * resolution + 0.5 | 0; + viewport.height = frame.height * resolution + 0.5 | 0; + } else { + viewport.x = 0; + viewport.y = 0; + viewport.width = pixelWidth; + viewport.height = pixelHeight; + } + calculateProjection( + this.projectionMatrix, + 0, + 0, + viewport.width / source.resolution, + viewport.height / source.resolution, + !renderTarget.isRoot + ); + this.adaptor.startRenderPass(renderTarget, clear, clearColor, viewport); + if (didChange) { + this.onRenderTargetChange.emit(renderTarget); + } + return renderTarget; + } + clear(target, clear = CLEAR.ALL, clearColor) { + if (!clear) + return; + if (target) { + target = this.getRenderTarget(target); + } + this.adaptor.clear( + target || this.renderTarget, + clear, + clearColor, + this.viewport + ); + } + contextChange() { + this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null); + } + /** + * Push a render surface to the renderer. This will bind the render surface to the renderer, + * @param renderSurface - the render surface to push + * @param clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111 + * @param clearColor - the color to clear to + * @param frame - the frame to use when rendering to the render surface + */ + push(renderSurface, clear = CLEAR.ALL, clearColor, frame) { + const renderTarget = this.bind(renderSurface, clear, clearColor, frame); + this._renderTargetStack.push({ + renderTarget, + frame + }); + return renderTarget; + } + /** Pops the current render target from the renderer and restores the previous render target. */ + pop() { + this._renderTargetStack.pop(); + const currentRenderTargetData = this._renderTargetStack[this._renderTargetStack.length - 1]; + this.bind(currentRenderTargetData.renderTarget, false, null, currentRenderTargetData.frame); + } + /** + * Gets the render target from the provide render surface. Eg if its a texture, + * it will return the render target for the texture. + * If its a render target, it will return the same render target. + * @param renderSurface - the render surface to get the render target for + * @returns the render target for the render surface + */ + getRenderTarget(renderSurface) { + var _a; + if (renderSurface.isTexture) { + renderSurface = renderSurface.source; + } + return (_a = this._renderSurfaceToRenderTargetHash.get(renderSurface)) != null ? _a : this._initRenderTarget(renderSurface); + } + /** + * Copies a render surface to another texture + * @param sourceRenderSurfaceTexture - the render surface to copy from + * @param destinationTexture - the texture to copy to + * @param originSrc - the origin of the copy + * @param originSrc.x - the x origin of the copy + * @param originSrc.y - the y origin of the copy + * @param size - the size of the copy + * @param size.width - the width of the copy + * @param size.height - the height of the copy + * @param originDest - the destination origin (top left to paste from!) + * @param originDest.x - the x origin of the paste + * @param originDest.y - the y origin of the paste + */ + copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) { + if (originSrc.x < 0) { + size.width += originSrc.x; + originDest.x -= originSrc.x; + originSrc.x = 0; + } + if (originSrc.y < 0) { + size.height += originSrc.y; + originDest.y -= originSrc.y; + originSrc.y = 0; + } + const { pixelWidth, pixelHeight } = sourceRenderSurfaceTexture; + size.width = Math.min(size.width, pixelWidth - originSrc.x); + size.height = Math.min(size.height, pixelHeight - originSrc.y); + return this.adaptor.copyToTexture( + sourceRenderSurfaceTexture, + destinationTexture, + originSrc, + size, + originDest + ); + } + /** + * ensures that we have a depth stencil buffer available to render to + * This is used by the mask system to make sure we have a stencil buffer. + */ + ensureDepthStencil() { + if (!this.renderTarget.stencil) { + this.renderTarget.stencil = true; + this.adaptor.startRenderPass(this.renderTarget, false, null, this.viewport); + } + } + /** nukes the render target system */ + destroy() { + this._renderer = null; + this._renderSurfaceToRenderTargetHash.forEach((renderTarget, key) => { + if (renderTarget !== key) { + renderTarget.destroy(); + } + }); + this._renderSurfaceToRenderTargetHash.clear(); + this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null); + } + _initRenderTarget(renderSurface) { + let renderTarget = null; + if (CanvasSource.test(renderSurface)) { + renderSurface = getCanvasTexture(renderSurface).source; + } + if (renderSurface instanceof RenderTarget) { + renderTarget = renderSurface; + } else if (renderSurface instanceof TextureSource) { + renderTarget = new RenderTarget({ + colorTextures: [renderSurface] + }); + if (CanvasSource.test(renderSurface.source.resource)) { + renderTarget.isRoot = true; + } + renderSurface.once("destroy", () => { + renderTarget.destroy(); + const gpuRenderTarget = this._gpuRenderTargetHash[renderTarget.uid]; + if (gpuRenderTarget) { + this._gpuRenderTargetHash[renderTarget.uid] = null; + this.adaptor.destroyGpuRenderTarget(gpuRenderTarget); + } + }); + } + this._renderSurfaceToRenderTargetHash.set(renderSurface, renderTarget); + return renderTarget; + } + getGpuRenderTarget(renderTarget) { + return this._gpuRenderTargetHash[renderTarget.uid] || (this._gpuRenderTargetHash[renderTarget.uid] = this.adaptor.initGpuRenderTarget(renderTarget)); + } + } + + "use strict"; + class GlRenderTargetSystem extends RenderTargetSystem { + constructor(renderer) { + super(renderer); + this.adaptor = new GlRenderTargetAdaptor(); + this.adaptor.init(renderer, this); + } + } + /** @ignore */ + GlRenderTargetSystem.extension = { + type: [ExtensionType.WebGLSystem], + name: "renderTarget" + }; + + "use strict"; + + "use strict"; + class BufferResource extends EventEmitter { + /** + * Create a new Buffer Resource. + * @param options - The options for the buffer resource + * @param options.buffer - The underlying buffer that this resource is using + * @param options.offset - The offset of the buffer this resource is using. + * If not provided, then it will use the offset of the buffer. + * @param options.size - The size of the buffer this resource is using. + * If not provided, then it will use the size of the buffer. + */ + constructor({ buffer, offset, size }) { + super(); + /** + * emits when the underlying buffer has changed shape (i.e. resized) + * letting the renderer know that it needs to discard the old buffer on the GPU and create a new one + * @event change + */ + /** + * a unique id for this uniform group used through the renderer + * @internal + * @ignore + */ + this.uid = uid("buffer"); + /** + * a resource type, used to identify how to handle it when its in a bind group / shader resource + * @internal + * @ignore + */ + this._resourceType = "bufferResource"; + /** + * used internally to know if a uniform group was used in the last render pass + * @internal + * @ignore + */ + this._touched = 0; + /** + * the resource id used internally by the renderer to build bind group keys + * @internal + * @ignore + */ + this._resourceId = uid("resource"); + /** + * A cheeky hint to the GL renderer to let it know this is a BufferResource + * @internal + * @ignore + */ + this._bufferResource = true; + /** + * Has the Buffer resource been destroyed? + * @readonly + */ + this.destroyed = false; + this.buffer = buffer; + this.offset = offset | 0; + this.size = size; + this.buffer.on("change", this.onBufferChange, this); + } + onBufferChange() { + this._resourceId = uid("resource"); + this.emit("change", this); + } + /** + * Destroys this resource. Make sure the underlying buffer is not used anywhere else + * if you want to destroy it as well, or code will explode + * @param destroyBuffer - Should the underlying buffer be destroyed as well? + */ + destroy(destroyBuffer = false) { + this.destroyed = true; + if (destroyBuffer) { + this.buffer.destroy(); + } + this.emit("change", this); + this.buffer = null; + } + } + + "use strict"; + function generateShaderSyncCode(shader, shaderSystem) { + const funcFragments = []; + const headerFragments = [` + var g = s.groups; + var sS = r.shader; + var p = s.glProgram; + var ugS = r.uniformGroup; + var resources; + `]; + let addedTextreSystem = false; + let blockIndex = 0; + let textureCount = 0; + const programData = shaderSystem._getProgramData(shader.glProgram); + for (const i in shader.groups) { + const group = shader.groups[i]; + funcFragments.push(` + resources = g[${i}].resources; + `); + for (const j in group.resources) { + const resource = group.resources[j]; + if (resource instanceof UniformGroup) { + if (resource.ubo) { + funcFragments.push(` + sS.bindUniformBlock( + resources[${j}], + sS._uniformBindMap[${i}[${j}], + ${blockIndex++} + ); + `); + } else { + funcFragments.push(` + ugS.updateUniformGroup(resources[${j}], p, sD); + `); + } + } else if (resource instanceof BufferResource) { + funcFragments.push(` + sS.bindUniformBlock( + resources[${j}], + sS._uniformBindMap[${i}[${j}], + ${blockIndex++} + ); + `); + } else if (resource instanceof TextureSource) { + const uniformName = shader._uniformBindMap[i][j]; + const uniformData = programData.uniformData[uniformName]; + if (uniformData) { + if (!addedTextreSystem) { + addedTextreSystem = true; + headerFragments.push(` + var tS = r.texture; + `); + } + shaderSystem._gl.uniform1i(uniformData.location, textureCount); + funcFragments.push(` + tS.bind(resources[${j}], ${textureCount}); + `); + textureCount++; + } + } + } + } + const functionSource = [...headerFragments, ...funcFragments].join("\n"); + return new Function("r", "s", "sD", functionSource); + } + + "use strict"; + class IGLUniformData { + } + class GlProgramData { + /** + * Makes a new Pixi program. + * @param program - webgl program + * @param uniformData - uniforms + */ + constructor(program, uniformData) { + this.program = program; + this.uniformData = uniformData; + this.uniformGroups = {}; + this.uniformDirtyGroups = {}; + this.uniformBlockBindings = {}; + } + /** Destroys this program. */ + destroy() { + this.uniformData = null; + this.uniformGroups = null; + this.uniformDirtyGroups = null; + this.uniformBlockBindings = null; + this.program = null; + } + } + + "use strict"; + function compileShader(gl, type, src) { + const shader = gl.createShader(type); + gl.shaderSource(shader, src); + gl.compileShader(shader); + return shader; + } + + "use strict"; + function booleanArray(size) { + const array = new Array(size); + for (let i = 0; i < array.length; i++) { + array[i] = false; + } + return array; + } + function defaultValue(type, size) { + switch (type) { + case "float": + return 0; + case "vec2": + return new Float32Array(2 * size); + case "vec3": + return new Float32Array(3 * size); + case "vec4": + return new Float32Array(4 * size); + case "int": + case "uint": + case "sampler2D": + case "sampler2DArray": + return 0; + case "ivec2": + return new Int32Array(2 * size); + case "ivec3": + return new Int32Array(3 * size); + case "ivec4": + return new Int32Array(4 * size); + case "uvec2": + return new Uint32Array(2 * size); + case "uvec3": + return new Uint32Array(3 * size); + case "uvec4": + return new Uint32Array(4 * size); + case "bool": + return false; + case "bvec2": + return booleanArray(2 * size); + case "bvec3": + return booleanArray(3 * size); + case "bvec4": + return booleanArray(4 * size); + case "mat2": + return new Float32Array([ + 1, + 0, + 0, + 1 + ]); + case "mat3": + return new Float32Array([ + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1 + ]); + case "mat4": + return new Float32Array([ + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1 + ]); + } + return null; + } + + "use strict"; + let GL_TABLE = null; + const GL_TO_GLSL_TYPES = { + FLOAT: "float", + FLOAT_VEC2: "vec2", + FLOAT_VEC3: "vec3", + FLOAT_VEC4: "vec4", + INT: "int", + INT_VEC2: "ivec2", + INT_VEC3: "ivec3", + INT_VEC4: "ivec4", + UNSIGNED_INT: "uint", + UNSIGNED_INT_VEC2: "uvec2", + UNSIGNED_INT_VEC3: "uvec3", + UNSIGNED_INT_VEC4: "uvec4", + BOOL: "bool", + BOOL_VEC2: "bvec2", + BOOL_VEC3: "bvec3", + BOOL_VEC4: "bvec4", + FLOAT_MAT2: "mat2", + FLOAT_MAT3: "mat3", + FLOAT_MAT4: "mat4", + SAMPLER_2D: "sampler2D", + INT_SAMPLER_2D: "sampler2D", + UNSIGNED_INT_SAMPLER_2D: "sampler2D", + SAMPLER_CUBE: "samplerCube", + INT_SAMPLER_CUBE: "samplerCube", + UNSIGNED_INT_SAMPLER_CUBE: "samplerCube", + SAMPLER_2D_ARRAY: "sampler2DArray", + INT_SAMPLER_2D_ARRAY: "sampler2DArray", + UNSIGNED_INT_SAMPLER_2D_ARRAY: "sampler2DArray" + }; + const GLSL_TO_VERTEX_TYPES = { + float: "float32", + vec2: "float32x2", + vec3: "float32x3", + vec4: "float32x4", + int: "sint32", + ivec2: "sint32x2", + ivec3: "sint32x3", + ivec4: "sint32x4", + uint: "uint32", + uvec2: "uint32x2", + uvec3: "uint32x3", + uvec4: "uint32x4", + bool: "uint32", + bvec2: "uint32x2", + bvec3: "uint32x3", + bvec4: "uint32x4" + }; + function mapType(gl, type) { + if (!GL_TABLE) { + const typeNames = Object.keys(GL_TO_GLSL_TYPES); + GL_TABLE = {}; + for (let i = 0; i < typeNames.length; ++i) { + const tn = typeNames[i]; + GL_TABLE[gl[tn]] = GL_TO_GLSL_TYPES[tn]; + } + } + return GL_TABLE[type]; + } + function mapGlToVertexFormat(gl, type) { + const typeValue = mapType(gl, type); + return GLSL_TO_VERTEX_TYPES[typeValue] || "float32"; + } + + "use strict"; + function extractAttributesFromGlProgram(program, gl, sortAttributes = false) { + const attributes = {}; + const totalAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); + for (let i = 0; i < totalAttributes; i++) { + const attribData = gl.getActiveAttrib(program, i); + if (attribData.name.startsWith("gl_")) { + continue; + } + const format = mapGlToVertexFormat(gl, attribData.type); + attributes[attribData.name] = { + location: 0, + // set further down.. + format, + stride: getAttributeInfoFromFormat(format).stride, + offset: 0, + instance: false, + start: 0 + }; + } + const keys = Object.keys(attributes); + if (sortAttributes) { + keys.sort((a, b) => a > b ? 1 : -1); + for (let i = 0; i < keys.length; i++) { + attributes[keys[i]].location = i; + gl.bindAttribLocation(program, i, keys[i]); + } + gl.linkProgram(program); + } else { + for (let i = 0; i < keys.length; i++) { + attributes[keys[i]].location = gl.getAttribLocation(program, keys[i]); + } + } + return attributes; + } + + "use strict"; + function getUboData(program, gl) { + if (!gl.ACTIVE_UNIFORM_BLOCKS) + return {}; + const uniformBlocks = {}; + const totalUniformsBlocks = gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS); + for (let i = 0; i < totalUniformsBlocks; i++) { + const name = gl.getActiveUniformBlockName(program, i); + const uniformBlockIndex = gl.getUniformBlockIndex(program, name); + const size = gl.getActiveUniformBlockParameter(program, i, gl.UNIFORM_BLOCK_DATA_SIZE); + uniformBlocks[name] = { + name, + index: uniformBlockIndex, + size + }; + } + return uniformBlocks; + } + + "use strict"; + function getUniformData(program, gl) { + const uniforms = {}; + const totalUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); + for (let i = 0; i < totalUniforms; i++) { + const uniformData = gl.getActiveUniform(program, i); + const name = uniformData.name.replace(/\[.*?\]$/, ""); + const isArray = !!uniformData.name.match(/\[.*?\]$/); + const type = mapType(gl, uniformData.type); + uniforms[name] = { + name, + index: i, + type, + size: uniformData.size, + isArray, + value: defaultValue(type, uniformData.size) + }; + } + return uniforms; + } + + "use strict"; + function logPrettyShaderError(gl, shader) { + const shaderSrc = gl.getShaderSource(shader).split("\n").map((line, index) => `${index}: ${line}`); + const shaderLog = gl.getShaderInfoLog(shader); + const splitShader = shaderLog.split("\n"); + const dedupe = {}; + const lineNumbers = splitShader.map((line) => parseFloat(line.replace(/^ERROR\: 0\:([\d]+)\:.*$/, "$1"))).filter((n) => { + if (n && !dedupe[n]) { + dedupe[n] = true; + return true; + } + return false; + }); + const logArgs = [""]; + lineNumbers.forEach((number) => { + shaderSrc[number - 1] = `%c${shaderSrc[number - 1]}%c`; + logArgs.push("background: #FF0000; color:#FFFFFF; font-size: 10px", "font-size: 10px"); + }); + const fragmentSourceToLog = shaderSrc.join("\n"); + logArgs[0] = fragmentSourceToLog; + console.error(shaderLog); + console.groupCollapsed("click to view full shader code"); + console.warn(...logArgs); + console.groupEnd(); + } + function logProgramError(gl, program, vertexShader, fragmentShader) { + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { + logPrettyShaderError(gl, vertexShader); + } + if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { + logPrettyShaderError(gl, fragmentShader); + } + console.error("PixiJS Error: Could not initialize shader."); + if (gl.getProgramInfoLog(program) !== "") { + console.warn("PixiJS Warning: gl.getProgramInfoLog()", gl.getProgramInfoLog(program)); + } + } + } + + "use strict"; + function generateProgram(gl, program) { + const glVertShader = compileShader(gl, gl.VERTEX_SHADER, program.vertex); + const glFragShader = compileShader(gl, gl.FRAGMENT_SHADER, program.fragment); + const webGLProgram = gl.createProgram(); + gl.attachShader(webGLProgram, glVertShader); + gl.attachShader(webGLProgram, glFragShader); + const transformFeedbackVaryings = program.transformFeedbackVaryings; + if (transformFeedbackVaryings) { + if (typeof gl.transformFeedbackVaryings !== "function") { + warn(`TransformFeedback is not supported but TransformFeedbackVaryings are given.`); + } else { + gl.transformFeedbackVaryings( + webGLProgram, + transformFeedbackVaryings.names, + transformFeedbackVaryings.bufferMode === "separate" ? gl.SEPARATE_ATTRIBS : gl.INTERLEAVED_ATTRIBS + ); + } + } + gl.linkProgram(webGLProgram); + if (!gl.getProgramParameter(webGLProgram, gl.LINK_STATUS)) { + logProgramError(gl, webGLProgram, glVertShader, glFragShader); + } + program._attributeData = extractAttributesFromGlProgram( + webGLProgram, + gl, + !/^[ \t]*#[ \t]*version[ \t]+300[ \t]+es[ \t]*$/m.test(program.vertex) + ); + program._uniformData = getUniformData(webGLProgram, gl); + program._uniformBlockData = getUboData(webGLProgram, gl); + gl.deleteShader(glVertShader); + gl.deleteShader(glFragShader); + const uniformData = {}; + for (const i in program._uniformData) { + const data = program._uniformData[i]; + uniformData[i] = { + location: gl.getUniformLocation(webGLProgram, i), + value: defaultValue(data.type, data.size) + }; + } + const glProgram = new GlProgramData(webGLProgram, uniformData); + return glProgram; + } + + "use strict"; + const defaultSyncData = { + textureCount: 0, + blockIndex: 0 + }; + class GlShaderSystem { + constructor(renderer) { + /** + * @internal + * @private + */ + this._activeProgram = null; + this._programDataHash = /* @__PURE__ */ Object.create(null); + this._nextIndex = 0; + this._boundUniformsIdsToIndexHash = /* @__PURE__ */ Object.create(null); + this._boundIndexToUniformsHash = /* @__PURE__ */ Object.create(null); + this._shaderSyncFunctions = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + contextChange(gl) { + this._gl = gl; + this._maxBindings = gl.MAX_UNIFORM_BUFFER_BINDINGS ? gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS) : 0; + this._programDataHash = /* @__PURE__ */ Object.create(null); + this._boundUniformsIdsToIndexHash = /* @__PURE__ */ Object.create(null); + this._boundIndexToUniformsHash = /* @__PURE__ */ Object.create(null); + this._activeProgram = null; + } + /** + * Changes the current shader to the one given in parameter. + * @param shader - the new shader + * @param skipSync - false if the shader should automatically sync its uniforms. + * @returns the glProgram that belongs to the shader. + */ + bind(shader, skipSync) { + this._setProgram(shader.glProgram); + if (skipSync) + return; + defaultSyncData.textureCount = 0; + defaultSyncData.blockIndex = 0; + let syncFunction = this._shaderSyncFunctions[shader.glProgram._key]; + if (!syncFunction) { + syncFunction = this._shaderSyncFunctions[shader.glProgram._key] = this._generateShaderSync(shader, this); + } + syncFunction(this._renderer, shader, defaultSyncData); + } + /** + * Updates the uniform group. + * @param uniformGroup - the uniform group to update + */ + updateUniformGroup(uniformGroup) { + this._renderer.uniformGroup.updateUniformGroup(uniformGroup, this._activeProgram, defaultSyncData); + } + /** + * Binds a uniform block to the shader. + * @param uniformGroup - the uniform group to bind + * @param name - the name of the uniform block + * @param index - the index of the uniform block + */ + bindUniformBlock(uniformGroup, name, index = 0) { + const bufferSystem = this._renderer.buffer; + const programData = this._getProgramData(this._activeProgram); + const isBufferResource = uniformGroup._bufferResource; + if (isBufferResource) { + this._renderer.ubo.updateUniformGroup(uniformGroup); + } + bufferSystem.updateBuffer(uniformGroup.buffer); + let boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid]; + if (boundIndex === void 0) { + const nextIndex = this._nextIndex++ % this._maxBindings; + const currentBoundUniformGroup = this._boundIndexToUniformsHash[nextIndex]; + if (currentBoundUniformGroup) { + this._boundUniformsIdsToIndexHash[currentBoundUniformGroup.uid] = void 0; + } + boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid] = nextIndex; + this._boundIndexToUniformsHash[nextIndex] = uniformGroup; + if (isBufferResource) { + bufferSystem.bindBufferRange(uniformGroup.buffer, nextIndex, uniformGroup.offset); + } else { + bufferSystem.bindBufferBase(uniformGroup.buffer, nextIndex); + } + } + const gl = this._gl; + const uniformBlockIndex = this._activeProgram._uniformBlockData[name].index; + if (programData.uniformBlockBindings[index] === boundIndex) + return; + programData.uniformBlockBindings[index] = boundIndex; + gl.uniformBlockBinding(programData.program, uniformBlockIndex, boundIndex); + } + _setProgram(program) { + if (this._activeProgram === program) + return; + this._activeProgram = program; + const programData = this._getProgramData(program); + this._gl.useProgram(programData.program); + } + /** + * @param program - the program to get the data for + * @internal + * @private + */ + _getProgramData(program) { + return this._programDataHash[program._key] || this._createProgramData(program); + } + _createProgramData(program) { + const key = program._key; + this._programDataHash[key] = generateProgram(this._gl, program); + return this._programDataHash[key]; + } + destroy() { + for (const key of Object.keys(this._programDataHash)) { + const programData = this._programDataHash[key]; + programData.destroy(); + this._programDataHash[key] = null; + } + this._programDataHash = null; + this._boundUniformsIdsToIndexHash = null; + } + /** + * Creates a function that can be executed that will sync the shader as efficiently as possible. + * Overridden by the unsafe eval package if you don't want eval used in your project. + * @param shader - the shader to generate the sync function for + * @param shaderSystem - the shader system to use + * @returns - the generated sync function + * @ignore + */ + _generateShaderSync(shader, shaderSystem) { + return generateShaderSyncCode(shader, shaderSystem); + } + } + /** @ignore */ + GlShaderSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "shader" + }; + + "use strict"; + const UNIFORM_TO_SINGLE_SETTERS = { + f32: `if (cv !== v) { + cu.value = v; + gl.uniform1f(location, v); + }`, + "vec2": `if (cv[0] !== v[0] || cv[1] !== v[1]) { + cv[0] = v[0]; + cv[1] = v[1]; + gl.uniform2f(location, v[0], v[1]); + }`, + "vec3": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + gl.uniform3f(location, v[0], v[1], v[2]); + }`, + "vec4": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + cv[3] = v[3]; + gl.uniform4f(location, v[0], v[1], v[2], v[3]); + }`, + i32: `if (cv !== v) { + cu.value = v; + gl.uniform1i(location, v); + }`, + "vec2": `if (cv[0] !== v[0] || cv[1] !== v[1]) { + cv[0] = v[0]; + cv[1] = v[1]; + gl.uniform2i(location, v[0], v[1]); + }`, + "vec3": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + gl.uniform3i(location, v[0], v[1], v[2]); + }`, + "vec4": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + cv[3] = v[3]; + gl.uniform4i(location, v[0], v[1], v[2], v[3]); + }`, + u32: `if (cv !== v) { + cu.value = v; + gl.uniform1ui(location, v); + }`, + "vec2": `if (cv[0] !== v[0] || cv[1] !== v[1]) { + cv[0] = v[0]; + cv[1] = v[1]; + gl.uniform2ui(location, v[0], v[1]); + }`, + "vec3": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + gl.uniform3ui(location, v[0], v[1], v[2]); + }`, + "vec4": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + cv[3] = v[3]; + gl.uniform4ui(location, v[0], v[1], v[2], v[3]); + }`, + bool: `if (cv !== v) { + cu.value = v; + gl.uniform1i(location, v); + }`, + "vec2": `if (cv[0] !== v[0] || cv[1] !== v[1]) { + cv[0] = v[0]; + cv[1] = v[1]; + gl.uniform2i(location, v[0], v[1]); + }`, + "vec3": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + gl.uniform3i(location, v[0], v[1], v[2]); + }`, + "vec4": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) { + cv[0] = v[0]; + cv[1] = v[1]; + cv[2] = v[2]; + cv[3] = v[3]; + gl.uniform4i(location, v[0], v[1], v[2], v[3]); + }`, + "mat2x2": `gl.uniformMatrix2fv(location, false, v);`, + "mat3x3": `gl.uniformMatrix3fv(location, false, v);`, + "mat4x4": `gl.uniformMatrix4fv(location, false, v);` + }; + const UNIFORM_TO_ARRAY_SETTERS = { + f32: `gl.uniform1fv(location, v);`, + "vec2": `gl.uniform2fv(location, v);`, + "vec3": `gl.uniform3fv(location, v);`, + "vec4": `gl.uniform4fv(location, v);`, + "mat2x2": `gl.uniformMatrix2fv(location, false, v);`, + "mat3x3": `gl.uniformMatrix3fv(location, false, v);`, + "mat4x4": `gl.uniformMatrix4fv(location, false, v);`, + i32: `gl.uniform1iv(location, v);`, + "vec2": `gl.uniform2iv(location, v);`, + "vec3": `gl.uniform3iv(location, v);`, + "vec4": `gl.uniform4iv(location, v);`, + u32: `gl.uniform1iv(location, v);`, + "vec2": `gl.uniform2iv(location, v);`, + "vec3": `gl.uniform3iv(location, v);`, + "vec4": `gl.uniform4iv(location, v);`, + bool: `gl.uniform1iv(location, v);`, + "vec2": `gl.uniform2iv(location, v);`, + "vec3": `gl.uniform3iv(location, v);`, + "vec4": `gl.uniform4iv(location, v);` + }; + + "use strict"; + function generateUniformsSync(group, uniformData) { + const funcFragments = [` + var v = null; + var cv = null; + var cu = null; + var t = 0; + var gl = renderer.gl; + var name = null; + `]; + for (const i in group.uniforms) { + if (!uniformData[i]) { + if (group.uniforms[i] instanceof UniformGroup) { + if (group.uniforms[i].ubo) { + funcFragments.push(` + renderer.shader.bindUniformBlock(uv.${i}, "${i}"); + `); + } else { + funcFragments.push(` + renderer.shader.updateUniformGroup(uv.${i}); + `); + } + } else if (group.uniforms[i] instanceof BufferResource) { + funcFragments.push(` + renderer.shader.bindBufferResource(uv.${i}, "${i}"); + `); + } + continue; + } + const uniform = group.uniformStructures[i]; + let parsed = false; + for (let j = 0; j < uniformParsers.length; j++) { + const parser = uniformParsers[j]; + if (uniform.type === parser.type && parser.test(uniform)) { + funcFragments.push(`name = "${i}";`, uniformParsers[j].uniform); + parsed = true; + break; + } + } + if (!parsed) { + const templateType = uniform.size === 1 ? UNIFORM_TO_SINGLE_SETTERS : UNIFORM_TO_ARRAY_SETTERS; + const template = templateType[uniform.type].replace("location", `ud["${i}"].location`); + funcFragments.push(` + cu = ud["${i}"]; + cv = cu.value; + v = uv["${i}"]; + ${template};`); + } + } + return new Function("ud", "uv", "renderer", "syncData", funcFragments.join("\n")); + } + + "use strict"; + class GlUniformGroupSystem { + /** @param renderer - The renderer this System works for. */ + constructor(renderer) { + /** Cache to holds the generated functions. Stored against UniformObjects unique signature. */ + this._cache = {}; + this._uniformGroupSyncHash = {}; + this._renderer = renderer; + this.gl = null; + this._cache = {}; + } + contextChange(gl) { + this.gl = gl; + } + /** + * Uploads the uniforms values to the currently bound shader. + * @param group - the uniforms values that be applied to the current shader + * @param program + * @param syncData + * @param syncData.textureCount + */ + updateUniformGroup(group, program, syncData) { + const programData = this._renderer.shader._getProgramData(program); + if (!group.isStatic || group._dirtyId !== programData.uniformDirtyGroups[group.uid]) { + programData.uniformDirtyGroups[group.uid] = group._dirtyId; + const syncFunc = this._getUniformSyncFunction(group, program); + syncFunc(programData.uniformData, group.uniforms, this._renderer, syncData); + } + } + /** + * Overrideable by the pixi.js/unsafe-eval package to use static syncUniforms instead. + * @param group + * @param program + */ + _getUniformSyncFunction(group, program) { + var _a; + return ((_a = this._uniformGroupSyncHash[group._signature]) == null ? void 0 : _a[program._key]) || this._createUniformSyncFunction(group, program); + } + _createUniformSyncFunction(group, program) { + const uniformGroupSyncHash = this._uniformGroupSyncHash[group._signature] || (this._uniformGroupSyncHash[group._signature] = {}); + const id = this._getSignature(group, program._uniformData, "u"); + if (!this._cache[id]) { + this._cache[id] = this._generateUniformsSync(group, program._uniformData); + } + uniformGroupSyncHash[program._key] = this._cache[id]; + return uniformGroupSyncHash[program._key]; + } + _generateUniformsSync(group, uniformData) { + return generateUniformsSync(group, uniformData); + } + /** + * Takes a uniform group and data and generates a unique signature for them. + * @param group - The uniform group to get signature of + * @param group.uniforms + * @param uniformData - Uniform information generated by the shader + * @param preFix + * @returns Unique signature of the uniform group + */ + _getSignature(group, uniformData, preFix) { + const uniforms = group.uniforms; + const strings = [`${preFix}-`]; + for (const i in uniforms) { + strings.push(i); + if (uniformData[i]) { + strings.push(uniformData[i].type); + } + } + return strings.join("-"); + } + /** Destroys this System and removes all its textures. */ + destroy() { + this._renderer = null; + this._cache = null; + } + } + /** @ignore */ + GlUniformGroupSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "uniformGroup" + }; + + "use strict"; + function migrateFragmentFromV7toV8(fragmentShader) { + fragmentShader = fragmentShader.replaceAll("texture2D", "texture").replaceAll("gl_FragColor", "finalColor").replaceAll("varying", "in"); + fragmentShader = ` + out vec4 finalColor; + ${fragmentShader} + `; + return fragmentShader; + } + + "use strict"; + const GLSL_TO_SIZE = { + float: 1, + vec2: 2, + vec3: 3, + vec4: 4, + int: 1, + ivec2: 2, + ivec3: 3, + ivec4: 4, + uint: 1, + uvec2: 2, + uvec3: 3, + uvec4: 4, + bool: 1, + bvec2: 2, + bvec3: 3, + bvec4: 4, + mat2: 4, + mat3: 9, + mat4: 16, + sampler2D: 1 + }; + function mapSize(type) { + return GLSL_TO_SIZE[type]; + } + + "use strict"; + function mapWebGLBlendModesToPixi(gl) { + const blendMap = {}; + blendMap.normal = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + blendMap.add = [gl.ONE, gl.ONE]; + blendMap.multiply = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + blendMap.screen = [gl.ONE, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + blendMap.none = [0, 0]; + blendMap["normal-npm"] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + blendMap["add-npm"] = [gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE]; + blendMap["screen-npm"] = [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_COLOR, gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; + blendMap.erase = [gl.ZERO, gl.ONE_MINUS_SRC_ALPHA]; + return blendMap; + } + + "use strict"; + const BLEND = 0; + const OFFSET = 1; + const CULLING = 2; + const DEPTH_TEST = 3; + const WINDING = 4; + const DEPTH_MASK = 5; + const _GlStateSystem = class _GlStateSystem { + constructor() { + this.gl = null; + this.stateId = 0; + this.polygonOffset = 0; + this.blendMode = "none"; + this._blendEq = false; + this.map = []; + this.map[BLEND] = this.setBlend; + this.map[OFFSET] = this.setOffset; + this.map[CULLING] = this.setCullFace; + this.map[DEPTH_TEST] = this.setDepthTest; + this.map[WINDING] = this.setFrontFace; + this.map[DEPTH_MASK] = this.setDepthMask; + this.checks = []; + this.defaultState = State.for2d(); + } + contextChange(gl) { + this.gl = gl; + this.blendModesMap = mapWebGLBlendModesToPixi(gl); + this.reset(); + } + /** + * Sets the current state + * @param {*} state - The state to set. + */ + set(state) { + state = state || this.defaultState; + if (this.stateId !== state.data) { + let diff = this.stateId ^ state.data; + let i = 0; + while (diff) { + if (diff & 1) { + this.map[i].call(this, !!(state.data & 1 << i)); + } + diff = diff >> 1; + i++; + } + this.stateId = state.data; + } + for (let i = 0; i < this.checks.length; i++) { + this.checks[i](this, state); + } + } + /** + * Sets the state, when previous state is unknown. + * @param {*} state - The state to set + */ + forceState(state) { + state = state || this.defaultState; + for (let i = 0; i < this.map.length; i++) { + this.map[i].call(this, !!(state.data & 1 << i)); + } + for (let i = 0; i < this.checks.length; i++) { + this.checks[i](this, state); + } + this.stateId = state.data; + } + /** + * Sets whether to enable or disable blending. + * @param value - Turn on or off WebGl blending. + */ + setBlend(value) { + this._updateCheck(_GlStateSystem._checkBlendMode, value); + this.gl[value ? "enable" : "disable"](this.gl.BLEND); + } + /** + * Sets whether to enable or disable polygon offset fill. + * @param value - Turn on or off webgl polygon offset testing. + */ + setOffset(value) { + this._updateCheck(_GlStateSystem._checkPolygonOffset, value); + this.gl[value ? "enable" : "disable"](this.gl.POLYGON_OFFSET_FILL); + } + /** + * Sets whether to enable or disable depth test. + * @param value - Turn on or off webgl depth testing. + */ + setDepthTest(value) { + this.gl[value ? "enable" : "disable"](this.gl.DEPTH_TEST); + } + /** + * Sets whether to enable or disable depth mask. + * @param value - Turn on or off webgl depth mask. + */ + setDepthMask(value) { + this.gl.depthMask(value); + } + /** + * Sets whether to enable or disable cull face. + * @param {boolean} value - Turn on or off webgl cull face. + */ + setCullFace(value) { + this.gl[value ? "enable" : "disable"](this.gl.CULL_FACE); + } + /** + * Sets the gl front face. + * @param {boolean} value - true is clockwise and false is counter-clockwise + */ + setFrontFace(value) { + this.gl.frontFace(this.gl[value ? "CW" : "CCW"]); + } + /** + * Sets the blend mode. + * @param {number} value - The blend mode to set to. + */ + setBlendMode(value) { + if (!this.blendModesMap[value]) { + value = "normal"; + } + if (value === this.blendMode) { + return; + } + this.blendMode = value; + const mode = this.blendModesMap[value]; + const gl = this.gl; + if (mode.length === 2) { + gl.blendFunc(mode[0], mode[1]); + } else { + gl.blendFuncSeparate(mode[0], mode[1], mode[2], mode[3]); + } + if (mode.length === 6) { + this._blendEq = true; + gl.blendEquationSeparate(mode[4], mode[5]); + } else if (this._blendEq) { + this._blendEq = false; + gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); + } + } + /** + * Sets the polygon offset. + * @param {number} value - the polygon offset + * @param {number} scale - the polygon offset scale + */ + setPolygonOffset(value, scale) { + this.gl.polygonOffset(value, scale); + } + // used + /** Resets all the logic and disables the VAOs. */ + reset() { + this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false); + this.forceState(this.defaultState); + this._blendEq = true; + this.blendMode = ""; + this.setBlendMode("normal"); + } + /** + * Checks to see which updates should be checked based on which settings have been activated. + * + * For example, if blend is enabled then we should check the blend modes each time the state is changed + * or if polygon fill is activated then we need to check if the polygon offset changes. + * The idea is that we only check what we have too. + * @param func - the checking function to add or remove + * @param value - should the check function be added or removed. + */ + _updateCheck(func, value) { + const index = this.checks.indexOf(func); + if (value && index === -1) { + this.checks.push(func); + } else if (!value && index !== -1) { + this.checks.splice(index, 1); + } + } + /** + * A private little wrapper function that we call to check the blend mode. + * @param system - the System to perform the state check on + * @param state - the state that the blendMode will pulled from + */ + static _checkBlendMode(system, state) { + system.setBlendMode(state.blendMode); + } + /** + * A private little wrapper function that we call to check the polygon offset. + * @param system - the System to perform the state check on + * @param state - the state that the blendMode will pulled from + */ + static _checkPolygonOffset(system, state) { + system.setPolygonOffset(1, state.polygonOffset); + } + /** + * @ignore + */ + destroy() { + this.gl = null; + this.checks.length = 0; + } + }; + /** @ignore */ + _GlStateSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "state" + }; + let GlStateSystem = _GlStateSystem; + + "use strict"; + class GlTexture { + constructor(texture) { + this.target = GL_TARGETS.TEXTURE_2D; + this.texture = texture; + this.width = -1; + this.height = -1; + this.type = GL_TYPES.UNSIGNED_BYTE; + this.internalFormat = GL_FORMATS.RGBA; + this.format = GL_FORMATS.RGBA; + this.samplerType = 0; + } + } + + "use strict"; + const glUploadBufferImageResource = { + id: "buffer", + upload(source, glTexture, gl) { + if (glTexture.width === source.width || glTexture.height === source.height) { + gl.texSubImage2D( + gl.TEXTURE_2D, + 0, + 0, + 0, + source.width, + source.height, + glTexture.format, + glTexture.type, + source.resource + ); + } else { + gl.texImage2D( + glTexture.target, + 0, + glTexture.internalFormat, + source.width, + source.height, + 0, + glTexture.format, + glTexture.type, + source.resource + ); + } + glTexture.width = source.width; + glTexture.height = source.height; + } + }; + + "use strict"; + const compressedFormatMap = { + "bc1-rgba-unorm": true, + "bc1-rgba-unorm-srgb": true, + "bc2-rgba-unorm": true, + "bc2-rgba-unorm-srgb": true, + "bc3-rgba-unorm": true, + "bc3-rgba-unorm-srgb": true, + "bc4-r-unorm": true, + "bc4-r-snorm": true, + "bc5-rg-unorm": true, + "bc5-rg-snorm": true, + "bc6h-rgb-ufloat": true, + "bc6h-rgb-float": true, + "bc7-rgba-unorm": true, + "bc7-rgba-unorm-srgb": true, + // ETC2 compressed formats usable if "texture-compression-etc2" is both + // supported by the device/user agent and enabled in requestDevice. + "etc2-rgb8unorm": true, + "etc2-rgb8unorm-srgb": true, + "etc2-rgb8a1unorm": true, + "etc2-rgb8a1unorm-srgb": true, + "etc2-rgba8unorm": true, + "etc2-rgba8unorm-srgb": true, + "eac-r11unorm": true, + "eac-r11snorm": true, + "eac-rg11unorm": true, + "eac-rg11snorm": true, + // ASTC compressed formats usable if "texture-compression-astc" is both + // supported by the device/user agent and enabled in requestDevice. + "astc-4x4-unorm": true, + "astc-4x4-unorm-srgb": true, + "astc-5x4-unorm": true, + "astc-5x4-unorm-srgb": true, + "astc-5x5-unorm": true, + "astc-5x5-unorm-srgb": true, + "astc-6x5-unorm": true, + "astc-6x5-unorm-srgb": true, + "astc-6x6-unorm": true, + "astc-6x6-unorm-srgb": true, + "astc-8x5-unorm": true, + "astc-8x5-unorm-srgb": true, + "astc-8x6-unorm": true, + "astc-8x6-unorm-srgb": true, + "astc-8x8-unorm": true, + "astc-8x8-unorm-srgb": true, + "astc-10x5-unorm": true, + "astc-10x5-unorm-srgb": true, + "astc-10x6-unorm": true, + "astc-10x6-unorm-srgb": true, + "astc-10x8-unorm": true, + "astc-10x8-unorm-srgb": true, + "astc-10x10-unorm": true, + "astc-10x10-unorm-srgb": true, + "astc-12x10-unorm": true, + "astc-12x10-unorm-srgb": true, + "astc-12x12-unorm": true, + "astc-12x12-unorm-srgb": true + }; + const glUploadCompressedTextureResource = { + id: "compressed", + upload(source, glTexture, gl) { + gl.pixelStorei(gl.UNPACK_ALIGNMENT, 4); + let mipWidth = source.pixelWidth; + let mipHeight = source.pixelHeight; + const compressed = !!compressedFormatMap[source.format]; + for (let i = 0; i < source.resource.length; i++) { + const levelBuffer = source.resource[i]; + if (compressed) { + gl.compressedTexImage2D( + gl.TEXTURE_2D, + i, + glTexture.internalFormat, + mipWidth, + mipHeight, + 0, + levelBuffer + ); + } else { + gl.texImage2D( + gl.TEXTURE_2D, + i, + glTexture.internalFormat, + mipWidth, + mipHeight, + 0, + glTexture.format, + glTexture.type, + levelBuffer + ); + } + mipWidth = Math.max(mipWidth >> 1, 1); + mipHeight = Math.max(mipHeight >> 1, 1); + } + } + }; + + "use strict"; + const glUploadImageResource = { + id: "image", + upload(source, glTexture, gl, webGLVersion) { + const premultipliedAlpha = source.alphaMode === "premultiply-alpha-on-upload"; + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultipliedAlpha); + const glWidth = glTexture.width; + const glHeight = glTexture.height; + const textureWidth = source.pixelWidth; + const textureHeight = source.pixelHeight; + const resourceWidth = source.resourceWidth; + const resourceHeight = source.resourceHeight; + if (resourceWidth < textureWidth || resourceHeight < textureHeight) { + if (glWidth !== textureWidth || glHeight !== textureHeight) { + gl.texImage2D( + glTexture.target, + 0, + glTexture.internalFormat, + textureWidth, + textureHeight, + 0, + glTexture.format, + glTexture.type, + null + ); + } + if (webGLVersion === 2) { + gl.texSubImage2D( + gl.TEXTURE_2D, + 0, + 0, + 0, + resourceWidth, + resourceHeight, + glTexture.format, + glTexture.type, + source.resource + ); + } else { + gl.texSubImage2D( + gl.TEXTURE_2D, + 0, + 0, + 0, + glTexture.format, + glTexture.type, + source.resource + ); + } + } else if (glWidth === textureWidth || glHeight === textureHeight) { + gl.texSubImage2D( + gl.TEXTURE_2D, + 0, + 0, + 0, + glTexture.format, + glTexture.type, + source.resource + ); + } else if (webGLVersion === 2) { + gl.texImage2D( + glTexture.target, + 0, + glTexture.internalFormat, + textureWidth, + textureHeight, + 0, + glTexture.format, + glTexture.type, + source.resource + ); + } else { + gl.texImage2D( + glTexture.target, + 0, + glTexture.internalFormat, + glTexture.format, + glTexture.type, + source.resource + ); + } + glTexture.width = textureWidth; + glTexture.height = textureHeight; + } + }; + + "use strict"; + const glUploadVideoResource = { + id: "video", + upload(source, glTexture, gl, webGLVersion) { + if (!source.isValid) { + gl.texImage2D( + glTexture.target, + 0, + glTexture.internalFormat, + 1, + 1, + 0, + glTexture.format, + glTexture.type, + null + ); + return; + } + glUploadImageResource.upload(source, glTexture, gl, webGLVersion); + } + }; + + "use strict"; + const scaleModeToGlFilter = { + linear: 9729, + nearest: 9728 + }; + const mipmapScaleModeToGlFilter = { + linear: { + linear: 9987, + nearest: 9985 + }, + nearest: { + linear: 9986, + nearest: 9984 + } + }; + const wrapModeToGlAddress = { + "clamp-to-edge": 33071, + repeat: 10497, + "mirror-repeat": 33648 + }; + const compareModeToGlCompare = { + never: 512, + less: 513, + equal: 514, + "less-equal": 515, + greater: 516, + "not-equal": 517, + "greater-equal": 518, + always: 519 + }; + + "use strict"; + function applyStyleParams(style, gl, mipmaps, anisotropicExt, glFunctionName, firstParam, forceClamp, firstCreation) { + const castParam = firstParam; + if (!firstCreation || style.addressModeU !== "repeat" || style.addressModeV !== "repeat" || style.addressModeW !== "repeat") { + const wrapModeS = wrapModeToGlAddress[forceClamp ? "clamp-to-edge" : style.addressModeU]; + const wrapModeT = wrapModeToGlAddress[forceClamp ? "clamp-to-edge" : style.addressModeV]; + const wrapModeR = wrapModeToGlAddress[forceClamp ? "clamp-to-edge" : style.addressModeW]; + gl[glFunctionName](castParam, gl.TEXTURE_WRAP_S, wrapModeS); + gl[glFunctionName](castParam, gl.TEXTURE_WRAP_T, wrapModeT); + if (gl.TEXTURE_WRAP_R) + gl[glFunctionName](castParam, gl.TEXTURE_WRAP_R, wrapModeR); + } + if (!firstCreation || style.magFilter !== "linear") { + gl[glFunctionName](castParam, gl.TEXTURE_MAG_FILTER, scaleModeToGlFilter[style.magFilter]); + } + if (mipmaps) { + if (!firstCreation || style.mipmapFilter !== "linear") { + const glFilterMode = mipmapScaleModeToGlFilter[style.minFilter][style.mipmapFilter]; + gl[glFunctionName](castParam, gl.TEXTURE_MIN_FILTER, glFilterMode); + } + } else { + gl[glFunctionName](castParam, gl.TEXTURE_MIN_FILTER, scaleModeToGlFilter[style.minFilter]); + } + if (anisotropicExt && style.maxAnisotropy > 1) { + const level = Math.min(style.maxAnisotropy, gl.getParameter(anisotropicExt.MAX_TEXTURE_MAX_ANISOTROPY_EXT)); + gl[glFunctionName](castParam, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, level); + } + if (style.compare) { + gl[glFunctionName](castParam, gl.TEXTURE_COMPARE_FUNC, compareModeToGlCompare[style.compare]); + } + } + + "use strict"; + function mapFormatToGlFormat(gl) { + return { + // 8-bit formats + r8unorm: gl.RED, + r8snorm: gl.RED, + r8uint: gl.RED, + r8sint: gl.RED, + // 16-bit formats + r16uint: gl.RED, + r16sint: gl.RED, + r16float: gl.RED, + rg8unorm: gl.RG, + rg8snorm: gl.RG, + rg8uint: gl.RG, + rg8sint: gl.RG, + // 32-bit formats + r32uint: gl.RED, + r32sint: gl.RED, + r32float: gl.RED, + rg16uint: gl.RG, + rg16sint: gl.RG, + rg16float: gl.RG, + rgba8unorm: gl.RGBA, + "rgba8unorm-srgb": gl.RGBA, + // Packed 32-bit formats + rgba8snorm: gl.RGBA, + rgba8uint: gl.RGBA, + rgba8sint: gl.RGBA, + bgra8unorm: gl.RGBA, + "bgra8unorm-srgb": gl.RGBA, + rgb9e5ufloat: gl.RGB, + rgb10a2unorm: gl.RGBA, + rg11b10ufloat: gl.RGB, + // 64-bit formats + rg32uint: gl.RG, + rg32sint: gl.RG, + rg32float: gl.RG, + rgba16uint: gl.RGBA, + rgba16sint: gl.RGBA, + rgba16float: gl.RGBA, + // 128-bit formats + rgba32uint: gl.RGBA, + rgba32sint: gl.RGBA, + rgba32float: gl.RGBA, + // Depth/stencil formats + stencil8: gl.STENCIL_INDEX8, + depth16unorm: gl.DEPTH_COMPONENT, + depth24plus: gl.DEPTH_COMPONENT, + "depth24plus-stencil8": gl.DEPTH_STENCIL, + depth32float: gl.DEPTH_COMPONENT, + "depth32float-stencil8": gl.DEPTH_STENCIL + }; + } + + "use strict"; + var __defProp$e = Object.defineProperty; + var __defProps$6 = Object.defineProperties; + var __getOwnPropDescs$6 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$e = Object.getOwnPropertySymbols; + var __hasOwnProp$e = Object.prototype.hasOwnProperty; + var __propIsEnum$e = Object.prototype.propertyIsEnumerable; + var __defNormalProp$e = (obj, key, value) => key in obj ? __defProp$e(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$e = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$e.call(b, prop)) + __defNormalProp$e(a, prop, b[prop]); + if (__getOwnPropSymbols$e) + for (var prop of __getOwnPropSymbols$e(b)) { + if (__propIsEnum$e.call(b, prop)) + __defNormalProp$e(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$6 = (a, b) => __defProps$6(a, __getOwnPropDescs$6(b)); + function mapFormatToGlInternalFormat(gl, extensions) { + let srgb = {}; + let bgra8unorm = gl.RGBA; + if (!(gl instanceof DOMAdapter.get().getWebGLRenderingContext())) { + srgb = { + "rgba8unorm-srgb": gl.SRGB8_ALPHA8, + "bgra8unorm-srgb": gl.SRGB8_ALPHA8 + }; + bgra8unorm = gl.RGBA8; + } else if (extensions.srgb) { + srgb = { + "rgba8unorm-srgb": extensions.srgb.SRGB8_ALPHA8_EXT, + "bgra8unorm-srgb": extensions.srgb.SRGB8_ALPHA8_EXT + }; + } + return __spreadValues$e(__spreadValues$e(__spreadValues$e(__spreadValues$e(__spreadValues$e(__spreadValues$e(__spreadProps$6(__spreadValues$e({ + // 8-bit formats + r8unorm: gl.R8, + r8snorm: gl.R8_SNORM, + r8uint: gl.R8UI, + r8sint: gl.R8I, + // 16-bit formats + r16uint: gl.R16UI, + r16sint: gl.R16I, + r16float: gl.R16F, + rg8unorm: gl.RG8, + rg8snorm: gl.RG8_SNORM, + rg8uint: gl.RG8UI, + rg8sint: gl.RG8I, + // 32-bit formats + r32uint: gl.R32UI, + r32sint: gl.R32I, + r32float: gl.R32F, + rg16uint: gl.RG16UI, + rg16sint: gl.RG16I, + rg16float: gl.RG16F, + rgba8unorm: gl.RGBA + }, srgb), { + // Packed 32-bit formats + rgba8snorm: gl.RGBA8_SNORM, + rgba8uint: gl.RGBA8UI, + rgba8sint: gl.RGBA8I, + bgra8unorm, + rgb9e5ufloat: gl.RGB9_E5, + rgb10a2unorm: gl.RGB10_A2, + rg11b10ufloat: gl.R11F_G11F_B10F, + // 64-bit formats + rg32uint: gl.RG32UI, + rg32sint: gl.RG32I, + rg32float: gl.RG32F, + rgba16uint: gl.RGBA16UI, + rgba16sint: gl.RGBA16I, + rgba16float: gl.RGBA16F, + // 128-bit formats + rgba32uint: gl.RGBA32UI, + rgba32sint: gl.RGBA32I, + rgba32float: gl.RGBA32F, + // Depth/stencil formats + stencil8: gl.STENCIL_INDEX8, + depth16unorm: gl.DEPTH_COMPONENT16, + depth24plus: gl.DEPTH_COMPONENT24, + "depth24plus-stencil8": gl.DEPTH24_STENCIL8, + depth32float: gl.DEPTH_COMPONENT32F, + "depth32float-stencil8": gl.DEPTH32F_STENCIL8 + }), extensions.s3tc ? { + "bc1-rgba-unorm": extensions.s3tc.COMPRESSED_RGBA_S3TC_DXT1_EXT, + "bc2-rgba-unorm": extensions.s3tc.COMPRESSED_RGBA_S3TC_DXT3_EXT, + "bc3-rgba-unorm": extensions.s3tc.COMPRESSED_RGBA_S3TC_DXT5_EXT + } : {}), extensions.s3tc_sRGB ? { + "bc1-rgba-unorm-srgb": extensions.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, + "bc2-rgba-unorm-srgb": extensions.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, + "bc3-rgba-unorm-srgb": extensions.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT + } : {}), extensions.rgtc ? { + "bc4-r-unorm": extensions.rgtc.COMPRESSED_RED_RGTC1_EXT, + "bc4-r-snorm": extensions.rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT, + "bc5-rg-unorm": extensions.rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT, + "bc5-rg-snorm": extensions.rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT + } : {}), extensions.bptc ? { + "bc6h-rgb-float": extensions.bptc.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT, + "bc6h-rgb-ufloat": extensions.bptc.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT, + "bc7-rgba-unorm": extensions.bptc.COMPRESSED_RGBA_BPTC_UNORM_EXT, + "bc7-rgba-unorm-srgb": extensions.bptc.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT + } : {}), extensions.etc ? { + "etc2-rgb8unorm": extensions.etc.COMPRESSED_RGB8_ETC2, + "etc2-rgb8unorm-srgb": extensions.etc.COMPRESSED_SRGB8_ETC2, + "etc2-rgb8a1unorm": extensions.etc.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, + "etc2-rgb8a1unorm-srgb": extensions.etc.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, + "etc2-rgba8unorm": extensions.etc.COMPRESSED_RGBA8_ETC2_EAC, + "etc2-rgba8unorm-srgb": extensions.etc.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC, + "eac-r11unorm": extensions.etc.COMPRESSED_R11_EAC, + // 'eac-r11snorm' + "eac-rg11unorm": extensions.etc.COMPRESSED_SIGNED_RG11_EAC + // 'eac-rg11snorm' + } : {}), extensions.astc ? { + "astc-4x4-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_4x4_KHR, + "astc-4x4-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, + "astc-5x4-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_5x4_KHR, + "astc-5x4-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR, + "astc-5x5-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_5x5_KHR, + "astc-5x5-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR, + "astc-6x5-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_6x5_KHR, + "astc-6x5-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR, + "astc-6x6-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_6x6_KHR, + "astc-6x6-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, + "astc-8x5-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_8x5_KHR, + "astc-8x5-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR, + "astc-8x6-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_8x6_KHR, + "astc-8x6-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR, + "astc-8x8-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_8x8_KHR, + "astc-8x8-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, + "astc-10x5-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_10x5_KHR, + "astc-10x5-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR, + "astc-10x6-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_10x6_KHR, + "astc-10x6-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR, + "astc-10x8-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_10x8_KHR, + "astc-10x8-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR, + "astc-10x10-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_10x10_KHR, + "astc-10x10-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, + "astc-12x10-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_12x10_KHR, + "astc-12x10-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, + "astc-12x12-unorm": extensions.astc.COMPRESSED_RGBA_ASTC_12x12_KHR, + "astc-12x12-unorm-srgb": extensions.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR + } : {}); + } + + "use strict"; + function mapFormatToGlType(gl) { + return { + // 8-bit formats + r8unorm: gl.UNSIGNED_BYTE, + r8snorm: gl.BYTE, + r8uint: gl.UNSIGNED_BYTE, + r8sint: gl.BYTE, + // 16-bit formats + r16uint: gl.UNSIGNED_SHORT, + r16sint: gl.SHORT, + r16float: gl.HALF_FLOAT, + rg8unorm: gl.UNSIGNED_BYTE, + rg8snorm: gl.BYTE, + rg8uint: gl.UNSIGNED_BYTE, + rg8sint: gl.BYTE, + // 32-bit formats + r32uint: gl.UNSIGNED_INT, + r32sint: gl.INT, + r32float: gl.FLOAT, + rg16uint: gl.UNSIGNED_SHORT, + rg16sint: gl.SHORT, + rg16float: gl.HALF_FLOAT, + rgba8unorm: gl.UNSIGNED_BYTE, + "rgba8unorm-srgb": gl.UNSIGNED_BYTE, + // Packed 32-bit formats + rgba8snorm: gl.BYTE, + rgba8uint: gl.UNSIGNED_BYTE, + rgba8sint: gl.BYTE, + bgra8unorm: gl.UNSIGNED_BYTE, + "bgra8unorm-srgb": gl.UNSIGNED_BYTE, + rgb9e5ufloat: gl.UNSIGNED_INT_5_9_9_9_REV, + rgb10a2unorm: gl.UNSIGNED_INT_2_10_10_10_REV, + rg11b10ufloat: gl.UNSIGNED_INT_10F_11F_11F_REV, + // 64-bit formats + rg32uint: gl.UNSIGNED_INT, + rg32sint: gl.INT, + rg32float: gl.FLOAT, + rgba16uint: gl.UNSIGNED_SHORT, + rgba16sint: gl.SHORT, + rgba16float: gl.HALF_FLOAT, + // 128-bit formats + rgba32uint: gl.UNSIGNED_INT, + rgba32sint: gl.INT, + rgba32float: gl.FLOAT, + // Depth/stencil formats + stencil8: gl.UNSIGNED_BYTE, + depth16unorm: gl.UNSIGNED_SHORT, + depth24plus: gl.UNSIGNED_INT, + "depth24plus-stencil8": gl.UNSIGNED_INT_24_8, + depth32float: gl.FLOAT, + "depth32float-stencil8": gl.FLOAT_32_UNSIGNED_INT_24_8_REV + }; + } + + "use strict"; + function unpremultiplyAlpha$1(pixels) { + if (pixels instanceof Uint8ClampedArray) { + pixels = new Uint8Array(pixels.buffer); + } + const n = pixels.length; + for (let i = 0; i < n; i += 4) { + const alpha = pixels[i + 3]; + if (alpha !== 0) { + const a = 255.001 / alpha; + pixels[i] = pixels[i] * a + 0.5; + pixels[i + 1] = pixels[i + 1] * a + 0.5; + pixels[i + 2] = pixels[i + 2] * a + 0.5; + } + } + } + + "use strict"; + const BYTES_PER_PIXEL = 4; + class GlTextureSystem { + constructor(renderer) { + this.managedTextures = []; + this._glTextures = /* @__PURE__ */ Object.create(null); + this._glSamplers = /* @__PURE__ */ Object.create(null); + this._boundTextures = []; + this._activeTextureLocation = -1; + this._boundSamplers = /* @__PURE__ */ Object.create(null); + this._uploads = { + image: glUploadImageResource, + buffer: glUploadBufferImageResource, + video: glUploadVideoResource, + compressed: glUploadCompressedTextureResource + }; + // TODO - separate samplers will be a cool thing to add, but not right now! + this._useSeparateSamplers = false; + this._renderer = renderer; + } + contextChange(gl) { + this._gl = gl; + if (!this._mapFormatToInternalFormat) { + this._mapFormatToInternalFormat = mapFormatToGlInternalFormat(gl, this._renderer.context.extensions); + this._mapFormatToType = mapFormatToGlType(gl); + this._mapFormatToFormat = mapFormatToGlFormat(gl); + } + this._glTextures = /* @__PURE__ */ Object.create(null); + this._glSamplers = /* @__PURE__ */ Object.create(null); + this._boundSamplers = /* @__PURE__ */ Object.create(null); + for (let i = 0; i < 16; i++) { + this.bind(Texture.EMPTY, i); + } + } + initSource(source) { + this.bind(source); + } + bind(texture, location = 0) { + const source = texture.source; + if (texture) { + this.bindSource(source, location); + if (this._useSeparateSamplers) { + this._bindSampler(source.style, location); + } + } else { + this.bindSource(null, location); + if (this._useSeparateSamplers) { + this._bindSampler(null, location); + } + } + } + bindSource(source, location = 0) { + const gl = this._gl; + source._touched = this._renderer.textureGC.count; + if (this._boundTextures[location] !== source) { + this._boundTextures[location] = source; + this._activateLocation(location); + source = source || Texture.EMPTY.source; + const glTexture = this.getGlSource(source); + gl.bindTexture(glTexture.target, glTexture.texture); + } + } + _bindSampler(style, location = 0) { + const gl = this._gl; + if (!style) { + this._boundSamplers[location] = null; + gl.bindSampler(location, null); + return; + } + const sampler = this._getGlSampler(style); + if (this._boundSamplers[location] !== sampler) { + this._boundSamplers[location] = sampler; + gl.bindSampler(location, sampler); + } + } + unbind(texture) { + const source = texture.source; + const boundTextures = this._boundTextures; + const gl = this._gl; + for (let i = 0; i < boundTextures.length; i++) { + if (boundTextures[i] === source) { + this._activateLocation(i); + const glTexture = this.getGlSource(source); + gl.bindTexture(glTexture.target, null); + boundTextures[i] = null; + } + } + } + _activateLocation(location) { + if (this._activeTextureLocation !== location) { + this._activeTextureLocation = location; + this._gl.activeTexture(this._gl.TEXTURE0 + location); + } + } + _initSource(source) { + const gl = this._gl; + const glTexture = new GlTexture(gl.createTexture()); + glTexture.type = this._mapFormatToType[source.format]; + glTexture.internalFormat = this._mapFormatToInternalFormat[source.format]; + glTexture.format = this._mapFormatToFormat[source.format]; + if (source.autoGenerateMipmaps && (this._renderer.context.supports.nonPowOf2mipmaps || source.isPowerOfTwo)) { + const biggestDimension = Math.max(source.width, source.height); + source.mipLevelCount = Math.floor(Math.log2(biggestDimension)) + 1; + } + this._glTextures[source.uid] = glTexture; + if (!this.managedTextures.includes(source)) { + source.on("update", this.onSourceUpdate, this); + source.on("resize", this.onSourceUpdate, this); + source.on("styleChange", this.onStyleChange, this); + source.on("destroy", this.onSourceDestroy, this); + source.on("unload", this.onSourceUnload, this); + source.on("updateMipmaps", this.onUpdateMipmaps, this); + this.managedTextures.push(source); + } + this.onSourceUpdate(source); + this.updateStyle(source, false); + return glTexture; + } + onStyleChange(source) { + this.updateStyle(source, false); + } + updateStyle(source, firstCreation) { + const gl = this._gl; + const glTexture = this.getGlSource(source); + gl.bindTexture(gl.TEXTURE_2D, glTexture.texture); + this._boundTextures[this._activeTextureLocation] = source; + applyStyleParams( + source.style, + gl, + source.mipLevelCount > 1, + this._renderer.context.extensions.anisotropicFiltering, + "texParameteri", + gl.TEXTURE_2D, + // will force a clamp to edge if the texture is not a power of two + !this._renderer.context.supports.nonPowOf2wrapping && !source.isPowerOfTwo, + firstCreation + ); + } + onSourceUnload(source) { + const glTexture = this._glTextures[source.uid]; + if (!glTexture) + return; + this.unbind(source); + this._glTextures[source.uid] = null; + this._gl.deleteTexture(glTexture.texture); + } + onSourceUpdate(source) { + const gl = this._gl; + const glTexture = this.getGlSource(source); + gl.bindTexture(gl.TEXTURE_2D, glTexture.texture); + this._boundTextures[this._activeTextureLocation] = source; + if (this._uploads[source.uploadMethodId]) { + this._uploads[source.uploadMethodId].upload(source, glTexture, gl, this._renderer.context.webGLVersion); + } else { + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, source.pixelWidth, source.pixelHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + } + if (source.autoGenerateMipmaps && source.mipLevelCount > 1) { + this.onUpdateMipmaps(source, false); + } + } + onUpdateMipmaps(source, bind = true) { + if (bind) + this.bindSource(source, 0); + const glTexture = this.getGlSource(source); + this._gl.generateMipmap(glTexture.target); + } + onSourceDestroy(source) { + source.off("destroy", this.onSourceDestroy, this); + source.off("update", this.onSourceUpdate, this); + source.off("resize", this.onSourceUpdate, this); + source.off("unload", this.onSourceUnload, this); + source.off("styleChange", this.onStyleChange, this); + source.off("updateMipmaps", this.onUpdateMipmaps, this); + this.managedTextures.splice(this.managedTextures.indexOf(source), 1); + this.onSourceUnload(source); + } + _initSampler(style) { + const gl = this._gl; + const glSampler = this._gl.createSampler(); + this._glSamplers[style._resourceId] = glSampler; + applyStyleParams( + style, + gl, + this._boundTextures[this._activeTextureLocation].mipLevelCount > 1, + this._renderer.context.extensions.anisotropicFiltering, + "samplerParameteri", + glSampler, + false, + true + ); + return this._glSamplers[style._resourceId]; + } + _getGlSampler(sampler) { + return this._glSamplers[sampler._resourceId] || this._initSampler(sampler); + } + getGlSource(source) { + return this._glTextures[source.uid] || this._initSource(source); + } + generateCanvas(texture) { + const { pixels, width, height } = this.getPixels(texture); + const canvas = DOMAdapter.get().createCanvas(); + canvas.width = width; + canvas.height = height; + const ctx = canvas.getContext("2d"); + if (ctx) { + const imageData = ctx.createImageData(width, height); + imageData.data.set(pixels); + ctx.putImageData(imageData, 0, 0); + } + return canvas; + } + getPixels(texture) { + const resolution = texture.source.resolution; + const frame = texture.frame; + const width = Math.max(Math.round(frame.width * resolution), 1); + const height = Math.max(Math.round(frame.height * resolution), 1); + const pixels = new Uint8Array(BYTES_PER_PIXEL * width * height); + const renderer = this._renderer; + const renderTarget = renderer.renderTarget.getRenderTarget(texture); + const glRenterTarget = renderer.renderTarget.getGpuRenderTarget(renderTarget); + const gl = renderer.gl; + gl.bindFramebuffer(gl.FRAMEBUFFER, glRenterTarget.resolveTargetFramebuffer); + gl.readPixels( + Math.round(frame.x * resolution), + Math.round(frame.y * resolution), + width, + height, + gl.RGBA, + gl.UNSIGNED_BYTE, + pixels + ); + if (false) { + unpremultiplyAlpha(pixels); + } + return { pixels: new Uint8ClampedArray(pixels.buffer), width, height }; + } + destroy() { + this.managedTextures.slice().forEach((source) => this.onSourceDestroy(source)); + this.managedTextures = null; + this._renderer = null; + } + } + /** @ignore */ + GlTextureSystem.extension = { + type: [ + ExtensionType.WebGLSystem + ], + name: "texture" + }; + + "use strict"; + + "use strict"; + class GlGraphicsAdaptor { + init() { + const uniforms = new UniformGroup({ + uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4" }, + uTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + uRound: { value: 0, type: "f32" } + }); + const maxTextures = maxRecommendedTextures(); + const glProgram = compileHighShaderGlProgram({ + name: "graphics", + bits: [ + colorBitGl, + generateTextureBatchBitGl(maxTextures), + localUniformBitGl, + roundPixelsBitGl + ] + }); + this.shader = new Shader({ + glProgram, + resources: { + localUniforms: uniforms, + batchSamplers: getBatchSamplersUniformGroup(maxTextures) + } + }); + } + execute(graphicsPipe, renderable) { + const context = renderable.context; + const shader = context.customShader || this.shader; + const renderer = graphicsPipe.renderer; + const contextSystem = renderer.graphicsContext; + const { + geometry, + instructions + } = contextSystem.getContextRenderData(context); + shader.groups[0] = renderer.globalUniforms.bindGroup; + renderer.state.set(graphicsPipe.state); + renderer.shader.bind(shader); + renderer.geometry.bind(geometry, shader.glProgram); + const batches = instructions.instructions; + for (let i = 0; i < instructions.instructionSize; i++) { + const batch = batches[i]; + if (batch.size) { + for (let j = 0; j < batch.textures.textures.length; j++) { + renderer.texture.bind(batch.textures.textures[j], j); + } + renderer.geometry.draw("triangle-list", batch.size, batch.start); + } + } + } + destroy() { + this.shader.destroy(true); + this.shader = null; + } + } + /** @ignore */ + GlGraphicsAdaptor.extension = { + type: [ + ExtensionType.WebGLPipesAdaptor + ], + name: "graphics" + }; + + "use strict"; + class GlMeshAdaptor { + init() { + const glProgram = compileHighShaderGlProgram({ + name: "mesh", + bits: [ + localUniformBitGl, + textureBitGl, + roundPixelsBitGl + ] + }); + this._shader = new Shader({ + glProgram, + resources: { + uTexture: Texture.EMPTY.source, + textureUniforms: { + uTextureMatrix: { type: "mat3x3", value: new Matrix() } + } + } + }); + } + execute(meshPipe, mesh) { + const renderer = meshPipe.renderer; + let shader = mesh._shader; + if (!shader) { + shader = this._shader; + const texture = mesh.texture; + const source = texture.source; + shader.resources.uTexture = source; + shader.resources.uSampler = source.style; + shader.resources.textureUniforms.uniforms.uTextureMatrix = texture.textureMatrix.mapCoord; + } else if (!shader.glProgram) { + warn("Mesh shader has no glProgram", mesh.shader); + return; + } + shader.groups[100] = renderer.globalUniforms.bindGroup; + shader.groups[101] = meshPipe.localUniformsBindGroup; + renderer.encoder.draw({ + geometry: mesh._geometry, + shader, + state: mesh.state + }); + } + destroy() { + this._shader.destroy(true); + this._shader = null; + } + } + GlMeshAdaptor.extension = { + type: [ + ExtensionType.WebGLPipesAdaptor + ], + name: "mesh" + }; + + "use strict"; + class CustomRenderPipe { + constructor(renderer) { + this._renderer = renderer; + } + addRenderable(container, instructionSet) { + this._renderer.renderPipes.batch.break(instructionSet); + instructionSet.add(container); + } + execute(container) { + if (!container.isRenderable) + return; + container.render(this._renderer); + } + destroy() { + this._renderer = null; + } + } + CustomRenderPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "customRender" + }; + + "use strict"; + function executeInstructions(renderGroup, renderer) { + const instructionSet = renderGroup.instructionSet; + const instructions = instructionSet.instructions; + for (let i = 0; i < instructionSet.instructionSize; i++) { + const instruction = instructions[i]; + renderer[instruction.renderPipeId].execute(instruction); + } + } + + "use strict"; + class RenderGroupPipe { + constructor(renderer) { + this._renderer = renderer; + } + addRenderGroup(renderGroup, instructionSet) { + this._renderer.renderPipes.batch.break(instructionSet); + instructionSet.add(renderGroup); + } + execute(renderGroup) { + if (!renderGroup.isRenderable) + return; + this._renderer.globalUniforms.push({ + worldTransformMatrix: renderGroup.worldTransform, + worldColor: renderGroup.worldColorAlpha + }); + executeInstructions(renderGroup, this._renderer.renderPipes); + this._renderer.globalUniforms.pop(); + } + destroy() { + this._renderer = null; + } + } + RenderGroupPipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "renderGroup" + }; + + "use strict"; + function collectRenderGroups(renderGroup, out = []) { + out.push(renderGroup); + for (let i = 0; i < renderGroup.renderGroupChildren.length; i++) { + collectRenderGroups(renderGroup.renderGroupChildren[i], out); + } + return out; + } + + "use strict"; + function mixHexColors(color1, color2, ratio) { + const r1 = color1 >> 16 & 255; + const g1 = color1 >> 8 & 255; + const b1 = color1 & 255; + const r2 = color2 >> 16 & 255; + const g2 = color2 >> 8 & 255; + const b2 = color2 & 255; + const r = r1 + (r2 - r1) * ratio; + const g = g1 + (g2 - g1) * ratio; + const b = b1 + (b2 - b1) * ratio; + return (r << 16) + (g << 8) + b; + } + + "use strict"; + const WHITE_BGR = 16777215; + function mixColors(localBGRColor, parentBGRColor) { + if (localBGRColor === WHITE_BGR || parentBGRColor === WHITE_BGR) { + return localBGRColor + parentBGRColor - WHITE_BGR; + } + return mixHexColors(localBGRColor, parentBGRColor, 0.5); + } + function mixStandardAnd32BitColors(localColorRGB, localAlpha, parentColor) { + const parentAlpha = (parentColor >> 24 & 255) / 255; + const globalAlpha = localAlpha * parentAlpha * 255; + const localBGRColor = ((localColorRGB & 255) << 16) + (localColorRGB & 65280) + (localColorRGB >> 16 & 255); + const parentBGRColor = parentColor & 16777215; + let sharedBGRColor; + if (localBGRColor === WHITE_BGR || parentBGRColor === WHITE_BGR) { + sharedBGRColor = localBGRColor + parentBGRColor - WHITE_BGR; + } else { + sharedBGRColor = mixHexColors(localBGRColor, parentBGRColor, 0.5); + } + return sharedBGRColor + (globalAlpha << 24); + } + + "use strict"; + const tempContainer = new Container(); + function updateRenderGroupTransforms(renderGroup, updateChildRenderGroups = false) { + updateRenderGroupTransform(renderGroup); + const childrenToUpdate = renderGroup.childrenToUpdate; + const updateTick = renderGroup.updateTick++; + for (const j in childrenToUpdate) { + const childrenAtDepth = childrenToUpdate[j]; + const list = childrenAtDepth.list; + const index = childrenAtDepth.index; + for (let i = 0; i < index; i++) { + const child = list[i]; + if (child.parentRenderGroup === renderGroup) { + updateTransformAndChildren(child, updateTick, 0); + } + } + childrenAtDepth.index = 0; + } + if (updateChildRenderGroups) { + for (let i = 0; i < renderGroup.renderGroupChildren.length; i++) { + updateRenderGroupTransforms(renderGroup.renderGroupChildren[i], updateChildRenderGroups); + } + } + } + function updateRenderGroupTransform(renderGroup) { + const root = renderGroup.root; + let worldAlpha; + if (renderGroup.renderGroupParent) { + const renderGroupParent = renderGroup.renderGroupParent; + renderGroup.worldTransform.appendFrom( + root.relativeGroupTransform, + renderGroupParent.worldTransform + ); + renderGroup.worldColor = mixColors( + root.groupColor, + renderGroupParent.worldColor + ); + worldAlpha = root.groupAlpha * renderGroupParent.worldAlpha; + } else { + renderGroup.worldTransform.copyFrom(root.localTransform); + renderGroup.worldColor = root.localColor; + worldAlpha = root.localAlpha; + } + worldAlpha = worldAlpha < 0 ? 0 : worldAlpha > 1 ? 1 : worldAlpha; + renderGroup.worldAlpha = worldAlpha; + renderGroup.worldColorAlpha = renderGroup.worldColor + ((worldAlpha * 255 | 0) << 24); + } + function updateTransformAndChildren(container, updateTick, updateFlags) { + if (updateTick === container.updateTick) + return; + container.updateTick = updateTick; + container.didChange = false; + const localTransform = container.localTransform; + container.updateLocalTransform(); + const parent = container.parent; + if (parent && !parent.renderGroup) { + updateFlags = updateFlags | container._updateFlags; + container.relativeGroupTransform.appendFrom( + localTransform, + parent.relativeGroupTransform + ); + if (updateFlags) { + updateColorBlendVisibility(container, parent, updateFlags); + } + } else { + updateFlags = container._updateFlags; + container.relativeGroupTransform.copyFrom(localTransform); + if (updateFlags) { + updateColorBlendVisibility(container, tempContainer, updateFlags); + } + } + if (!container.renderGroup) { + const children = container.children; + const length = children.length; + for (let i = 0; i < length; i++) { + updateTransformAndChildren(children[i], updateTick, updateFlags); + } + const renderGroup = container.parentRenderGroup; + if (container.renderPipeId && !renderGroup.structureDidChange) { + renderGroup.updateRenderable(container); + } + } + } + function updateColorBlendVisibility(container, parent, updateFlags) { + if (updateFlags & UPDATE_COLOR) { + container.groupColor = mixColors( + container.localColor, + parent.groupColor + ); + let groupAlpha = container.localAlpha * parent.groupAlpha; + groupAlpha = groupAlpha < 0 ? 0 : groupAlpha > 1 ? 1 : groupAlpha; + container.groupAlpha = groupAlpha; + container.groupColorAlpha = container.groupColor + ((groupAlpha * 255 | 0) << 24); + } + if (updateFlags & UPDATE_BLEND) { + container.groupBlendMode = container.localBlendMode === "inherit" ? parent.groupBlendMode : container.localBlendMode; + } + if (updateFlags & UPDATE_VISIBLE) { + container.globalDisplayStatus = container.localDisplayStatus & parent.globalDisplayStatus; + } + container._updateFlags = 0; + } + + "use strict"; + function validateRenderables(renderGroup, renderPipes) { + const { list, index } = renderGroup.childrenRenderablesToUpdate; + let rebuildRequired = false; + for (let i = 0; i < index; i++) { + const container = list[i]; + const renderable = container; + const pipe = renderPipes[renderable.renderPipeId]; + rebuildRequired = pipe.validateRenderable(container); + if (rebuildRequired) { + break; + } + } + renderGroup.structureDidChange = rebuildRequired; + return rebuildRequired; + } + + "use strict"; + const tempMatrix = new Matrix(); + class RenderGroupSystem { + constructor(renderer) { + this._renderer = renderer; + } + render({ container, transform }) { + container.isRenderGroup = true; + const parent = container.parent; + const renderGroupParent = container.renderGroup.renderGroupParent; + container.parent = null; + container.renderGroup.renderGroupParent = null; + const renderer = this._renderer; + const renderGroups = collectRenderGroups(container.renderGroup, []); + let originalLocalTransform = tempMatrix; + if (transform) { + originalLocalTransform = originalLocalTransform.copyFrom(container.renderGroup.localTransform); + container.renderGroup.localTransform.copyFrom(transform); + } + const renderPipes = renderer.renderPipes; + for (let i = 0; i < renderGroups.length; i++) { + const renderGroup = renderGroups[i]; + renderGroup.runOnRender(); + renderGroup.instructionSet.renderPipes = renderPipes; + if (!renderGroup.structureDidChange) { + validateRenderables(renderGroup, renderPipes); + } + updateRenderGroupTransforms(renderGroup); + if (renderGroup.structureDidChange) { + renderGroup.structureDidChange = false; + buildInstructions(renderGroup, renderPipes); + } else { + updateRenderables(renderGroup); + } + renderGroup.childrenRenderablesToUpdate.index = 0; + renderer.renderPipes.batch.upload(renderGroup.instructionSet); + } + renderer.globalUniforms.start({ + worldTransformMatrix: transform ? container.renderGroup.localTransform : container.renderGroup.worldTransform, + worldColor: container.renderGroup.worldColorAlpha + }); + executeInstructions(container.renderGroup, renderPipes); + if (renderPipes.uniformBatch) { + renderPipes.uniformBatch.renderEnd(); + } + if (transform) { + container.renderGroup.localTransform.copyFrom(originalLocalTransform); + } + container.parent = parent; + container.renderGroup.renderGroupParent = renderGroupParent; + } + destroy() { + this._renderer = null; + } + } + /** @ignore */ + RenderGroupSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "renderGroup" + }; + function updateRenderables(renderGroup) { + const { list, index } = renderGroup.childrenRenderablesToUpdate; + for (let i = 0; i < index; i++) { + const container = list[i]; + if (container.didViewUpdate) { + renderGroup.updateRenderable(container); + } + } + } + + "use strict"; + class SpritePipe { + constructor(renderer) { + this._gpuSpriteHash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + addRenderable(sprite, _instructionSet) { + const gpuSprite = this._getGpuSprite(sprite); + if (sprite._didSpriteUpdate) + this._updateBatchableSprite(sprite, gpuSprite); + this._renderer.renderPipes.batch.addToBatch(gpuSprite); + } + updateRenderable(sprite) { + const gpuSprite = this._gpuSpriteHash[sprite.uid]; + if (sprite._didSpriteUpdate) + this._updateBatchableSprite(sprite, gpuSprite); + gpuSprite.batcher.updateElement(gpuSprite); + } + validateRenderable(sprite) { + const texture = sprite._texture; + const gpuSprite = this._getGpuSprite(sprite); + if (gpuSprite.texture._source !== texture._source) { + return !gpuSprite.batcher.checkAndUpdateTexture(gpuSprite, texture); + } + return false; + } + destroyRenderable(sprite) { + const batchableSprite = this._gpuSpriteHash[sprite.uid]; + BigPool.return(batchableSprite); + this._gpuSpriteHash[sprite.uid] = null; + } + _updateBatchableSprite(sprite, batchableSprite) { + sprite._didSpriteUpdate = false; + batchableSprite.bounds = sprite.bounds; + batchableSprite.texture = sprite._texture; + } + _getGpuSprite(sprite) { + return this._gpuSpriteHash[sprite.uid] || this._initGPUSprite(sprite); + } + _initGPUSprite(sprite) { + const batchableSprite = BigPool.get(BatchableSprite); + batchableSprite.renderable = sprite; + batchableSprite.texture = sprite._texture; + batchableSprite.bounds = sprite.bounds; + batchableSprite.roundPixels = this._renderer._roundPixels | sprite._roundPixels; + this._gpuSpriteHash[sprite.uid] = batchableSprite; + sprite._didSpriteUpdate = false; + sprite.on("destroyed", () => { + this.destroyRenderable(sprite); + }); + return batchableSprite; + } + destroy() { + for (const i in this._gpuSpriteHash) { + BigPool.return(this._gpuSpriteHash[i]); + } + this._gpuSpriteHash = null; + this._renderer = null; + } + } + /** @ignore */ + SpritePipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "sprite" + }; + + "use strict"; + var __defProp$d = Object.defineProperty; + var __getOwnPropSymbols$d = Object.getOwnPropertySymbols; + var __hasOwnProp$d = Object.prototype.hasOwnProperty; + var __propIsEnum$d = Object.prototype.propertyIsEnumerable; + var __defNormalProp$d = (obj, key, value) => key in obj ? __defProp$d(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$d = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$d.call(b, prop)) + __defNormalProp$d(a, prop, b[prop]); + if (__getOwnPropSymbols$d) + for (var prop of __getOwnPropSymbols$d(b)) { + if (__propIsEnum$d.call(b, prop)) + __defNormalProp$d(a, prop, b[prop]); + } + return a; + }; + const _BackgroundSystem = class _BackgroundSystem { + constructor() { + this.clearBeforeRender = true; + this._backgroundColor = new Color(0); + this.color = this._backgroundColor; + this.alpha = 1; + } + /** + * initiates the background system + * @param options - the options for the background colors + */ + init(options) { + options = __spreadValues$d(__spreadValues$d({}, _BackgroundSystem.defaultOptions), options); + this.clearBeforeRender = options.clearBeforeRender; + this.color = options.background || options.backgroundColor || this._backgroundColor; + this.alpha = options.backgroundAlpha; + this._backgroundColor.setAlpha(options.backgroundAlpha); + } + /** The background color to fill if not transparent */ + get color() { + return this._backgroundColor; + } + set color(value) { + this._backgroundColor.setValue(value); + } + /** The background color alpha. Setting this to 0 will make the canvas transparent. */ + get alpha() { + return this._backgroundColor.alpha; + } + set alpha(value) { + this._backgroundColor.setAlpha(value); + } + /** The background color as an [R, G, B, A] array. */ + get colorRgba() { + return this._backgroundColor.toArray(); + } + /** + * destroys the background system + * @internal + * @ignore + */ + destroy() { + } + }; + /** @ignore */ + _BackgroundSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "background", + priority: 0 + }; + /** default options used by the system */ + _BackgroundSystem.defaultOptions = { + /** + * {@link WebGLOptions.backgroundAlpha} + * @default 1 + */ + backgroundAlpha: 1, + /** + * {@link WebGLOptions.backgroundColor} + * @default 0x000000 + */ + backgroundColor: 0, + /** + * {@link WebGLOptions.clearBeforeRender} + * @default true + */ + clearBeforeRender: true + }; + let BackgroundSystem = _BackgroundSystem; + + "use strict"; + const BLEND_MODE_FILTERS = {}; + extensions.handle(ExtensionType.BlendMode, (value) => { + if (!value.name) { + throw new Error("BlendMode extension must have a name property"); + } + BLEND_MODE_FILTERS[value.name] = value.ref; + }, (value) => { + delete BLEND_MODE_FILTERS[value.name]; + }); + class BlendModePipe { + constructor(renderer) { + this._isAdvanced = false; + this._filterHash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + /** + * This ensures that a blendMode switch is added to the instruction set if the blend mode has changed. + * @param renderable - The renderable we are adding to the instruction set + * @param blendMode - The blend mode of the renderable + * @param instructionSet - The instruction set we are adding to + */ + setBlendMode(renderable, blendMode, instructionSet) { + if (this._activeBlendMode === blendMode) { + if (this._isAdvanced) + this._renderableList.push(renderable); + return; + } + this._activeBlendMode = blendMode; + if (this._isAdvanced) { + this._endAdvancedBlendMode(instructionSet); + } + this._isAdvanced = !!BLEND_MODE_FILTERS[blendMode]; + if (this._isAdvanced) { + this._beginAdvancedBlendMode(instructionSet); + this._renderableList.push(renderable); + } + } + _beginAdvancedBlendMode(instructionSet) { + this._renderer.renderPipes.batch.break(instructionSet); + const blendMode = this._activeBlendMode; + if (!BLEND_MODE_FILTERS[blendMode]) { + warn(`Unable to assign BlendMode: '${blendMode}'. You may want to include: import 'pixi.js/advanced-blend-modes'`); + return; + } + let filterEffect = this._filterHash[blendMode]; + if (!filterEffect) { + filterEffect = this._filterHash[blendMode] = new FilterEffect(); + filterEffect.filters = [new BLEND_MODE_FILTERS[blendMode]()]; + } + const instruction = { + renderPipeId: "filter", + action: "pushFilter", + renderables: [], + filterEffect, + canBundle: false + }; + this._renderableList = instruction.renderables; + instructionSet.add(instruction); + } + _endAdvancedBlendMode(instructionSet) { + this._renderableList = null; + this._renderer.renderPipes.batch.break(instructionSet); + instructionSet.add({ + renderPipeId: "filter", + action: "popFilter", + canBundle: false + }); + } + /** + * called when the instruction build process is starting this will reset internally to the default blend mode + * @internal + * @ignore + */ + buildStart() { + this._isAdvanced = false; + } + /** + * called when the instruction build process is finished, ensuring that if there is an advanced blend mode + * active, we add the final render instructions added to the instruction set + * @param instructionSet - The instruction set we are adding to + * @internal + * @ignore + */ + buildEnd(instructionSet) { + if (this._isAdvanced) { + this._endAdvancedBlendMode(instructionSet); + } + } + /** + * @internal + * @ignore + */ + destroy() { + this._renderer = null; + this._renderableList = null; + for (const i in this._filterHash) { + this._filterHash[i].destroy(); + } + this._filterHash = null; + } + } + /** @ignore */ + BlendModePipe.extension = { + type: [ + ExtensionType.WebGLPipes, + ExtensionType.WebGPUPipes, + ExtensionType.CanvasPipes + ], + name: "blendMode" + }; + + "use strict"; + var __defProp$c = Object.defineProperty; + var __getOwnPropSymbols$c = Object.getOwnPropertySymbols; + var __hasOwnProp$c = Object.prototype.hasOwnProperty; + var __propIsEnum$c = Object.prototype.propertyIsEnumerable; + var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$c = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$c.call(b, prop)) + __defNormalProp$c(a, prop, b[prop]); + if (__getOwnPropSymbols$c) + for (var prop of __getOwnPropSymbols$c(b)) { + if (__propIsEnum$c.call(b, prop)) + __defNormalProp$c(a, prop, b[prop]); + } + return a; + }; + const imageTypes = { + png: "image/png", + jpg: "image/jpeg", + webp: "image/webp" + }; + const _ExtractSystem = class _ExtractSystem { + /** @param renderer - The renderer this System works for. */ + constructor(renderer) { + this._renderer = renderer; + } + _normalizeOptions(options, defaults = {}) { + if (options instanceof Container || options instanceof Texture) { + return __spreadValues$c({ + target: options + }, defaults); + } + return __spreadValues$c(__spreadValues$c({}, defaults), options); + } + /** + * Will return a HTML Image of the target + * @param options - The options for creating the image, or the target to extract + * @returns - HTML Image of the target + */ + async image(options) { + const image = new Image(); + image.src = await this.base64(options); + return image; + } + /** + * Will return a base64 encoded string of this target. It works by calling + * `Extract.canvas` and then running toDataURL on that. + * @param options - The options for creating the image, or the target to extract + */ + async base64(options) { + options = this._normalizeOptions( + options, + _ExtractSystem.defaultImageOptions + ); + const { format, quality } = options; + const canvas = this.canvas(options); + if (canvas.toBlob !== void 0) { + return new Promise((resolve, reject) => { + canvas.toBlob((blob) => { + if (!blob) { + reject(new Error("ICanvas.toBlob failed!")); + return; + } + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(blob); + }, imageTypes[format], quality); + }); + } + if (canvas.toDataURL !== void 0) { + return canvas.toDataURL(imageTypes[format], quality); + } + if (canvas.convertToBlob !== void 0) { + const blob = await canvas.convertToBlob({ type: imageTypes[format], quality }); + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsDataURL(blob); + }); + } + throw new Error("Extract.base64() requires ICanvas.toDataURL, ICanvas.toBlob, or ICanvas.convertToBlob to be implemented"); + } + /** + * Creates a Canvas element, renders this target to it and then returns it. + * @param options - The options for creating the canvas, or the target to extract + * @returns - A Canvas element with the texture rendered on. + */ + canvas(options) { + options = this._normalizeOptions(options); + const target = options.target; + const renderer = this._renderer; + if (target instanceof Texture) { + return renderer.texture.generateCanvas(target); + } + const texture = renderer.textureGenerator.generateTexture(options); + const canvas = renderer.texture.generateCanvas(texture); + texture.destroy(); + return canvas; + } + /** + * Will return a one-dimensional array containing the pixel data of the entire texture in RGBA + * order, with integer values between 0 and 255 (included). + * @param options - The options for extracting the image, or the target to extract + * @returns - One-dimensional array containing the pixel data of the entire texture + */ + pixels(options) { + options = this._normalizeOptions(options); + const target = options.target; + const renderer = this._renderer; + const texture = target instanceof Texture ? target : renderer.textureGenerator.generateTexture(options); + const pixelInfo = renderer.texture.getPixels(texture); + if (target instanceof Container) { + texture.destroy(); + } + return pixelInfo; + } + /** + * Will return a texture of the target + * @param options - The options for creating the texture, or the target to extract + * @returns - A texture of the target + */ + texture(options) { + options = this._normalizeOptions(options); + if (options.target instanceof Texture) + return options.target; + return this._renderer.textureGenerator.generateTexture(options); + } + /** + * Will extract a HTMLImage of the target and download it + * @param options - The options for downloading and extracting the image, or the target to extract + */ + download(options) { + var _a; + options = this._normalizeOptions(options); + const canvas = this.canvas(options); + const link = document.createElement("a"); + link.download = (_a = options.filename) != null ? _a : "image.png"; + link.href = canvas.toDataURL("image/png"); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + /** + * Logs the target to the console as an image. This is a useful way to debug what's happening in the renderer. + * @param options - The options for logging the image, or the target to log + */ + log(options) { + var _a; + const width = (_a = options.width) != null ? _a : 200; + options = this._normalizeOptions(options); + const canvas = this.canvas(options); + const base64 = canvas.toDataURL(); + console.log(`[Pixi Texture] ${canvas.width}px ${canvas.height}px`); + const style = [ + "font-size: 1px;", + `padding: ${width}px ${300}px;`, + `background: url(${base64}) no-repeat;`, + "background-size: contain;" + ].join(" "); + console.log("%c ", style); + } + destroy() { + this._renderer = null; + } + }; + /** @ignore */ + _ExtractSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "extract" + }; + /** Default options for creating an image. */ + _ExtractSystem.defaultImageOptions = { + /** The format of the image. */ + format: "png", + /** The quality of the image. */ + quality: 1 + }; + let ExtractSystem = _ExtractSystem; + + "use strict"; + class RenderTexture extends Texture { + static create(options) { + return new Texture({ + source: new TextureSource(options) + }); + } + /** + * Resizes the render texture. + * @param width - The new width of the render texture. + * @param height - The new height of the render texture. + * @param resolution - The new resolution of the render texture. + * @returns This texture. + */ + resize(width, height, resolution) { + this.source.resize(width, height, resolution); + return this; + } + } + + "use strict"; + var __defProp$b = Object.defineProperty; + var __defProps$5 = Object.defineProperties; + var __getOwnPropDescs$5 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$b = Object.getOwnPropertySymbols; + var __hasOwnProp$b = Object.prototype.hasOwnProperty; + var __propIsEnum$b = Object.prototype.propertyIsEnumerable; + var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$b = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$b.call(b, prop)) + __defNormalProp$b(a, prop, b[prop]); + if (__getOwnPropSymbols$b) + for (var prop of __getOwnPropSymbols$b(b)) { + if (__propIsEnum$b.call(b, prop)) + __defNormalProp$b(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$5 = (a, b) => __defProps$5(a, __getOwnPropDescs$5(b)); + const tempRect = new Rectangle(); + const tempBounds = new Bounds(); + const noColor = [0, 0, 0, 0]; + class GenerateTextureSystem { + constructor(renderer) { + this._renderer = renderer; + } + /** + * A Useful function that returns a texture of the display object that can then be used to create sprites + * This can be quite useful if your container is complicated and needs to be reused multiple times. + * @param {GenerateTextureOptions | Container} options - Generate texture options. + * @param {Container} [options.container] - If not given, the renderer's resolution is used. + * @param {Rectangle} options.region - The region of the container, that shall be rendered, + * @param {number} [options.resolution] - The resolution of the texture being generated. + * if no region is specified, defaults to the local bounds of the container. + * @param {GenerateTextureSourceOptions} [options.textureSourceOptions] - Texture options for GPU. + * @returns a shiny new texture of the container passed in + */ + generateTexture(options) { + var _a; + if (options instanceof Container) { + options = { + target: options, + frame: void 0, + textureSourceOptions: {}, + resolution: void 0 + }; + } + const resolution = options.resolution || this._renderer.resolution; + const antialias = options.antialias || this._renderer.view.antialias; + const container = options.target; + let clearColor = options.clearColor; + if (clearColor) { + const isRGBAArray = Array.isArray(clearColor) && clearColor.length === 4; + clearColor = isRGBAArray ? clearColor : Color.shared.setValue(clearColor).toArray(); + } else { + clearColor = noColor; + } + const region = ((_a = options.frame) == null ? void 0 : _a.copyTo(tempRect)) || getLocalBounds(container, tempBounds).rectangle; + region.width = Math.max(region.width, 1 / resolution) | 0; + region.height = Math.max(region.height, 1 / resolution) | 0; + const target = RenderTexture.create(__spreadProps$5(__spreadValues$b({}, options.textureSourceOptions), { + width: region.width, + height: region.height, + resolution, + antialias + })); + const transform = Matrix.shared.translate(-region.x, -region.y); + this._renderer.render({ + container, + transform, + target, + clearColor + }); + return target; + } + destroy() { + this._renderer = null; + } + } + /** @ignore */ + GenerateTextureSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "textureGenerator" + }; + + "use strict"; + class GlobalUniformSystem { + constructor(renderer) { + this._stackIndex = 0; + this._globalUniformDataStack = []; + this._uniformsPool = []; + this._activeUniforms = []; + this._bindGroupPool = []; + this._activeBindGroups = []; + this._renderer = renderer; + } + reset() { + this._stackIndex = 0; + for (let i = 0; i < this._activeUniforms.length; i++) { + this._uniformsPool.push(this._activeUniforms[i]); + } + for (let i = 0; i < this._activeBindGroups.length; i++) { + this._bindGroupPool.push(this._activeBindGroups[i]); + } + this._activeUniforms.length = 0; + this._activeBindGroups.length = 0; + } + start(options) { + this.reset(); + this.push(options); + } + bind({ + size, + projectionMatrix, + worldTransformMatrix, + worldColor, + offset + }) { + const renderTarget = this._renderer.renderTarget.renderTarget; + const currentGlobalUniformData = this._stackIndex ? this._globalUniformDataStack[this._stackIndex - 1] : { + projectionData: renderTarget, + worldTransformMatrix: new Matrix(), + worldColor: 4294967295, + offset: new Point() + }; + const globalUniformData = { + projectionMatrix: projectionMatrix || this._renderer.renderTarget.projectionMatrix, + resolution: size || renderTarget.size, + worldTransformMatrix: worldTransformMatrix || currentGlobalUniformData.worldTransformMatrix, + worldColor: worldColor || currentGlobalUniformData.worldColor, + offset: offset || currentGlobalUniformData.offset, + bindGroup: null + }; + const uniformGroup = this._uniformsPool.pop() || this._createUniforms(); + this._activeUniforms.push(uniformGroup); + const uniforms = uniformGroup.uniforms; + uniforms.uProjectionMatrix = globalUniformData.projectionMatrix; + uniforms.uResolution = globalUniformData.resolution; + uniforms.uWorldTransformMatrix.copyFrom(globalUniformData.worldTransformMatrix); + uniforms.uWorldTransformMatrix.tx -= globalUniformData.offset.x; + uniforms.uWorldTransformMatrix.ty -= globalUniformData.offset.y; + color32BitToUniform( + globalUniformData.worldColor, + uniforms.uWorldColorAlpha, + 0 + ); + uniformGroup.update(); + let bindGroup; + if (this._renderer.renderPipes.uniformBatch) { + bindGroup = this._renderer.renderPipes.uniformBatch.getUniformBindGroup(uniformGroup, false); + } else { + bindGroup = this._bindGroupPool.pop() || new BindGroup(); + this._activeBindGroups.push(bindGroup); + bindGroup.setResource(uniformGroup, 0); + } + globalUniformData.bindGroup = bindGroup; + this._currentGlobalUniformData = globalUniformData; + } + push(options) { + this.bind(options); + this._globalUniformDataStack[this._stackIndex++] = this._currentGlobalUniformData; + } + pop() { + this._currentGlobalUniformData = this._globalUniformDataStack[--this._stackIndex - 1]; + if (this._renderer.type === RendererType.WEBGL) { + this._currentGlobalUniformData.bindGroup.resources[0].update(); + } + } + get bindGroup() { + return this._currentGlobalUniformData.bindGroup; + } + get uniformGroup() { + return this._currentGlobalUniformData.bindGroup.resources[0]; + } + _createUniforms() { + const globalUniforms = new UniformGroup({ + uProjectionMatrix: { value: new Matrix(), type: "mat3x3" }, + uWorldTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + // TODO - someone smart - set this to be a unorm8x4 rather than a vec4 + uWorldColorAlpha: { value: new Float32Array(4), type: "vec4" }, + uResolution: { value: [0, 0], type: "vec2" } + }, { + isStatic: true + }); + return globalUniforms; + } + destroy() { + this._renderer = null; + } + } + /** @ignore */ + GlobalUniformSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "globalUniforms" + }; + + "use strict"; + let saidHello = false; + const VERSION = "8.1.6"; + function sayHello(type) { + if (saidHello) { + return; + } + if (DOMAdapter.get().getNavigator().userAgent.toLowerCase().indexOf("chrome") > -1) { + const args = [ + `%c %c %c %c %c PixiJS %c v${VERSION} (${type}) http://www.pixijs.com/ + +`, + "background: #E72264; padding:5px 0;", + "background: #6CA2EA; padding:5px 0;", + "background: #B5D33D; padding:5px 0;", + "background: #FED23F; padding:5px 0;", + "color: #FFFFFF; background: #E72264; padding:5px 0;", + "color: #E72264; background: #FFFFFF; padding:5px 0;" + ]; + globalThis.console.log(...args); + } else if (globalThis.console) { + globalThis.console.log(`PixiJS ${VERSION} - ${type} - http://www.pixijs.com/`); + } + saidHello = true; + } + + "use strict"; + class HelloSystem { + constructor(renderer) { + this._renderer = renderer; + } + /** + * It all starts here! This initiates every system, passing in the options for any system by name. + * @param options - the config for the renderer and all its systems + */ + init(options) { + if (options.hello) { + let name = this._renderer.name; + if (this._renderer.type === RendererType.WEBGL) { + name += ` ${this._renderer.context.webGLVersion}`; + } + sayHello(name); + } + } + } + /** @ignore */ + HelloSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "hello", + priority: -2 + }; + /** The default options for the system. */ + HelloSystem.defaultOptions = { + /** {@link WebGLOptions.hello} */ + hello: false + }; + + "use strict"; + var __defProp$a = Object.defineProperty; + var __getOwnPropSymbols$a = Object.getOwnPropertySymbols; + var __hasOwnProp$a = Object.prototype.hasOwnProperty; + var __propIsEnum$a = Object.prototype.propertyIsEnumerable; + var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$a = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$a.call(b, prop)) + __defNormalProp$a(a, prop, b[prop]); + if (__getOwnPropSymbols$a) + for (var prop of __getOwnPropSymbols$a(b)) { + if (__propIsEnum$a.call(b, prop)) + __defNormalProp$a(a, prop, b[prop]); + } + return a; + }; + const _TextureGCSystem = class _TextureGCSystem { + /** @param renderer - The renderer this System works for. */ + constructor(renderer) { + this._renderer = renderer; + this.count = 0; + this.checkCount = 0; + } + init(options) { + options = __spreadValues$a(__spreadValues$a({}, _TextureGCSystem.defaultOptions), options); + this.checkCountMax = options.textureGCCheckCountMax; + this.maxIdle = options.textureGCAMaxIdle; + this.active = options.textureGCActive; + } + /** + * Checks to see when the last time a texture was used. + * If the texture has not been used for a specified amount of time, it will be removed from the GPU. + */ + postrender() { + if (!this._renderer.renderingToScreen) { + return; + } + this.count++; + if (!this.active) + return; + this.checkCount++; + if (this.checkCount > this.checkCountMax) { + this.checkCount = 0; + this.run(); + } + } + /** + * Checks to see when the last time a texture was used. + * If the texture has not been used for a specified amount of time, it will be removed from the GPU. + */ + run() { + const managedTextures = this._renderer.texture.managedTextures; + for (let i = 0; i < managedTextures.length; i++) { + const texture = managedTextures[i]; + if (texture.autoGarbageCollect && texture.resource && texture._touched > -1 && this.count - texture._touched > this.maxIdle) { + texture._touched = -1; + texture.unload(); + } + } + } + destroy() { + this._renderer = null; + } + }; + /** @ignore */ + _TextureGCSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem + ], + name: "textureGC" + }; + /** default options for the TextureGCSystem */ + _TextureGCSystem.defaultOptions = { + /** + * If set to true, this will enable the garbage collector on the GPU. + * @default true + */ + textureGCActive: true, + /** + * The maximum idle frames before a texture is destroyed by garbage collection. + * @default 60 * 60 + */ + textureGCAMaxIdle: 60 * 60, + /** + * Frames between two garbage collections. + * @default 600 + */ + textureGCCheckCountMax: 600 + }; + let TextureGCSystem = _TextureGCSystem; + extensions.add(TextureGCSystem); + + "use strict"; + var __defProp$9 = Object.defineProperty; + var __getOwnPropSymbols$9 = Object.getOwnPropertySymbols; + var __hasOwnProp$9 = Object.prototype.hasOwnProperty; + var __propIsEnum$9 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$9 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$9.call(b, prop)) + __defNormalProp$9(a, prop, b[prop]); + if (__getOwnPropSymbols$9) + for (var prop of __getOwnPropSymbols$9(b)) { + if (__propIsEnum$9.call(b, prop)) + __defNormalProp$9(a, prop, b[prop]); + } + return a; + }; + const _ViewSystem = class _ViewSystem { + /** The resolution / device pixel ratio of the renderer. */ + get resolution() { + return this.texture.source._resolution; + } + set resolution(value) { + this.texture.source.resize( + this.texture.source.width, + this.texture.source.height, + value + ); + } + /** + * initiates the view system + * @param options - the options for the view + */ + init(options) { + options = __spreadValues$9(__spreadValues$9({}, _ViewSystem.defaultOptions), options); + if (options.view) { + deprecation(v8_0_0, "ViewSystem.view has been renamed to ViewSystem.canvas"); + options.canvas = options.view; + } + this.screen = new Rectangle(0, 0, options.width, options.height); + this.canvas = options.canvas || DOMAdapter.get().createCanvas(); + this.antialias = !!options.antialias; + this.texture = getCanvasTexture(this.canvas, options); + this.renderTarget = new RenderTarget({ + colorTextures: [this.texture], + depth: !!options.depth, + isRoot: true + }); + this.texture.source.transparent = options.backgroundAlpha < 1; + this.multiView = !!options.multiView; + if (this.autoDensity) { + this.canvas.style.width = `${this.texture.width}px`; + this.canvas.style.height = `${this.texture.height}px`; + } + this.resolution = options.resolution; + } + /** + * Resizes the screen and canvas to the specified dimensions. + * @param desiredScreenWidth - The new width of the screen. + * @param desiredScreenHeight - The new height of the screen. + * @param resolution + */ + resize(desiredScreenWidth, desiredScreenHeight, resolution) { + this.texture.source.resize(desiredScreenWidth, desiredScreenHeight, resolution); + this.screen.width = this.texture.frame.width; + this.screen.height = this.texture.frame.height; + if (this.autoDensity) { + this.canvas.style.width = `${desiredScreenWidth}px`; + this.canvas.style.height = `${desiredScreenHeight}px`; + } + } + /** + * Destroys this System and optionally removes the canvas from the dom. + * @param {options | false} options - The options for destroying the view, or "false". + * @param options.removeView - Whether to remove the view element from the DOM. Defaults to `false`. + */ + destroy(options = false) { + const removeView = typeof options === "boolean" ? options : !!(options == null ? void 0 : options.removeView); + if (removeView && this.canvas.parentNode) { + this.canvas.parentNode.removeChild(this.canvas); + } + } + }; + /** @ignore */ + _ViewSystem.extension = { + type: [ + ExtensionType.WebGLSystem, + ExtensionType.WebGPUSystem, + ExtensionType.CanvasSystem + ], + name: "view", + priority: 0 + }; + /** The default options for the view system. */ + _ViewSystem.defaultOptions = { + /** + * {@link WebGLOptions.width} + * @default 800 + */ + width: 800, + /** + * {@link WebGLOptions.height} + * @default 600 + */ + height: 600, + /** + * {@link WebGLOptions.autoDensity} + * @default false + */ + autoDensity: false, + /** + * {@link WebGLOptions.antialias} + * @default false + */ + antialias: false + }; + let ViewSystem = _ViewSystem; + + "use strict"; + const SharedSystems = [ + BackgroundSystem, + GlobalUniformSystem, + HelloSystem, + ViewSystem, + RenderGroupSystem, + TextureGCSystem, + GenerateTextureSystem, + ExtractSystem + ]; + const SharedRenderPipes = [ + BlendModePipe, + BatcherPipe, + SpritePipe, + RenderGroupPipe, + AlphaMaskPipe, + StencilMaskPipe, + ColorMaskPipe, + CustomRenderPipe + ]; + + "use strict"; + const DefaultWebGLSystems = [ + ...SharedSystems, + GlUboSystem, + GlBackBufferSystem, + GlContextSystem, + GlBufferSystem, + GlTextureSystem, + GlRenderTargetSystem, + GlGeometrySystem, + GlUniformGroupSystem, + GlShaderSystem, + GlEncoderSystem, + GlStateSystem, + GlStencilSystem, + GlColorMaskSystem + ]; + const DefaultWebGLPipes = [...SharedRenderPipes]; + const DefaultWebGLAdapters = [GlBatchAdaptor, GlMeshAdaptor, GlGraphicsAdaptor]; + const systems$1 = []; + const renderPipes$1 = []; + const renderPipeAdaptors$1 = []; + extensions.handleByNamedList(ExtensionType.WebGLSystem, systems$1); + extensions.handleByNamedList(ExtensionType.WebGLPipes, renderPipes$1); + extensions.handleByNamedList(ExtensionType.WebGLPipesAdaptor, renderPipeAdaptors$1); + extensions.add(...DefaultWebGLSystems, ...DefaultWebGLPipes, ...DefaultWebGLAdapters); + class WebGLRenderer extends AbstractRenderer { + constructor() { + const systemConfig = { + name: "webgl", + type: RendererType.WEBGL, + systems: systems$1, + renderPipes: renderPipes$1, + renderPipeAdaptors: renderPipeAdaptors$1 + }; + super(systemConfig); + } + } + + var WebGLRenderer$1 = { + __proto__: null, + WebGLRenderer: WebGLRenderer + }; + + "use strict"; + class BindGroupSystem { + constructor(renderer) { + this._hash = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + contextChange(gpu) { + this._gpu = gpu; + } + getBindGroup(bindGroup, program, groupIndex) { + bindGroup._updateKey(); + const gpuBindGroup = this._hash[bindGroup._key] || this._createBindGroup(bindGroup, program, groupIndex); + return gpuBindGroup; + } + _createBindGroup(group, program, groupIndex) { + var _a; + const device = this._gpu.device; + const groupLayout = program.layout[groupIndex]; + const entries = []; + const renderer = this._renderer; + for (const j in groupLayout) { + const resource = (_a = group.resources[j]) != null ? _a : group.resources[groupLayout[j]]; + let gpuResource; + if (resource._resourceType === "uniformGroup") { + const uniformGroup = resource; + renderer.ubo.updateUniformGroup(uniformGroup); + const buffer = uniformGroup.buffer; + gpuResource = { + buffer: renderer.buffer.getGPUBuffer(buffer), + offset: 0, + size: buffer.descriptor.size + }; + } else if (resource._resourceType === "buffer") { + const buffer = resource; + gpuResource = { + buffer: renderer.buffer.getGPUBuffer(buffer), + offset: 0, + size: buffer.descriptor.size + }; + } else if (resource._resourceType === "bufferResource") { + const bufferResource = resource; + gpuResource = { + buffer: renderer.buffer.getGPUBuffer(bufferResource.buffer), + offset: bufferResource.offset, + size: bufferResource.size + }; + } else if (resource._resourceType === "textureSampler") { + const sampler = resource; + gpuResource = renderer.texture.getGpuSampler(sampler); + } else if (resource._resourceType === "textureSource") { + const texture = resource; + gpuResource = renderer.texture.getGpuSource(texture).createView({}); + } + entries.push({ + binding: groupLayout[j], + resource: gpuResource + }); + } + const layout = renderer.shader.getProgramData(program).bindGroups[groupIndex]; + const gpuBindGroup = device.createBindGroup({ + layout, + entries + }); + this._hash[group._key] = gpuBindGroup; + return gpuBindGroup; + } + destroy() { + for (const key of Object.keys(this._hash)) { + this._hash[key] = null; + } + this._hash = null; + this._renderer = null; + } + } + /** @ignore */ + BindGroupSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "bindGroup" + }; + + "use strict"; + class GpuBufferSystem { + constructor() { + this._gpuBuffers = /* @__PURE__ */ Object.create(null); + this._managedBuffers = []; + } + contextChange(gpu) { + this._gpu = gpu; + } + getGPUBuffer(buffer) { + return this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer); + } + updateBuffer(buffer) { + const gpuBuffer = this._gpuBuffers[buffer.uid] || this.createGPUBuffer(buffer); + const data = buffer.data; + if (buffer._updateID && data) { + buffer._updateID = 0; + this._gpu.device.queue.writeBuffer( + gpuBuffer, + 0, + data.buffer, + 0, + // round to the nearest 4 bytes + (buffer._updateSize || data.byteLength) + 3 & ~3 + ); + } + return gpuBuffer; + } + /** dispose all WebGL resources of all managed buffers */ + destroyAll() { + for (const id in this._gpuBuffers) { + this._gpuBuffers[id].destroy(); + } + this._gpuBuffers = {}; + } + createGPUBuffer(buffer) { + if (!this._gpuBuffers[buffer.uid]) { + buffer.on("update", this.updateBuffer, this); + buffer.on("change", this.onBufferChange, this); + buffer.on("destroy", this.onBufferDestroy, this); + } + const gpuBuffer = this._gpu.device.createBuffer(buffer.descriptor); + buffer._updateID = 0; + if (buffer.data) { + fastCopy(buffer.data.buffer, gpuBuffer.getMappedRange()); + gpuBuffer.unmap(); + } + this._gpuBuffers[buffer.uid] = gpuBuffer; + this._managedBuffers.push(buffer); + return gpuBuffer; + } + onBufferChange(buffer) { + const gpuBuffer = this._gpuBuffers[buffer.uid]; + gpuBuffer.destroy(); + buffer._updateID = 0; + this._gpuBuffers[buffer.uid] = this.createGPUBuffer(buffer); + } + /** + * Disposes buffer + * @param buffer - buffer with data + */ + onBufferDestroy(buffer) { + this._managedBuffers.splice(this._managedBuffers.indexOf(buffer), 1); + this._destroyBuffer(buffer); + } + destroy() { + this._managedBuffers.forEach((buffer) => this._destroyBuffer(buffer)); + this._managedBuffers = null; + this._gpuBuffers = null; + } + _destroyBuffer(buffer) { + const gpuBuffer = this._gpuBuffers[buffer.uid]; + gpuBuffer.destroy(); + buffer.off("update", this.updateBuffer, this); + buffer.off("change", this.onBufferChange, this); + buffer.off("destroy", this.onBufferDestroy, this); + this._gpuBuffers[buffer.uid] = null; + } + } + /** @ignore */ + GpuBufferSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "buffer" + }; + + "use strict"; + function GpuReadBuffer(buffer, renderer) { + const bufferSize = buffer.descriptor.size; + const device = renderer.gpu.device; + const stagingBuffer = new Buffer({ + data: new Float32Array(24e5), + usage: BufferUsage.MAP_READ | BufferUsage.COPY_DST + }); + const stagingGPUBuffer = renderer.buffer.createGPUBuffer(stagingBuffer); + const commandEncoder = device.createCommandEncoder(); + commandEncoder.copyBufferToBuffer( + renderer.buffer.getGPUBuffer(buffer), + 0, + // Source offset + stagingGPUBuffer, + 0, + // Destination offset + bufferSize + ); + device.queue.submit([commandEncoder.finish()]); + void stagingGPUBuffer.mapAsync( + GPUMapMode.READ, + 0, + // Offset + bufferSize + // Length + ).then(() => { + stagingGPUBuffer.getMappedRange(0, bufferSize); + stagingGPUBuffer.unmap(); + }); + } + + "use strict"; + class UboBatch { + constructor({ minUniformOffsetAlignment }) { + this._minUniformOffsetAlignment = 256; + this.byteIndex = 0; + this._minUniformOffsetAlignment = minUniformOffsetAlignment; + this.data = new Float32Array(65535); + } + clear() { + this.byteIndex = 0; + } + addEmptyGroup(size) { + if (size > this._minUniformOffsetAlignment / 4) { + throw new Error(`UniformBufferBatch: array is too large: ${size * 4}`); + } + const start = this.byteIndex; + let newSize = start + size * 4; + newSize = Math.ceil(newSize / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment; + if (newSize > this.data.length * 4) { + throw new Error("UniformBufferBatch: ubo batch got too big"); + } + this.byteIndex = newSize; + return start; + } + addGroup(array) { + const offset = this.addEmptyGroup(array.length); + for (let i = 0; i < array.length; i++) { + this.data[offset / 4 + i] = array[i]; + } + return offset; + } + destroy() { + this._buffer.destroy(); + this._buffer = null; + this.data = null; + } + } + + "use strict"; + class GpuColorMaskSystem { + constructor(renderer) { + this._colorMaskCache = 15; + this._renderer = renderer; + } + setMask(colorMask) { + if (this._colorMaskCache === colorMask) + return; + this._colorMaskCache = colorMask; + this._renderer.pipeline.setColorMask(colorMask); + } + destroy() { + this._renderer = null; + this._colorMaskCache = null; + } + } + /** @ignore */ + GpuColorMaskSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "colorMask" + }; + + "use strict"; + class GpuDeviceSystem { + /** + * @param {WebGPURenderer} renderer - The renderer this System works for. + */ + constructor(renderer) { + this._renderer = renderer; + } + async init(options) { + if (this._initPromise) + return this._initPromise; + this._initPromise = this._createDeviceAndAdaptor(options).then((gpu) => { + this.gpu = gpu; + this._renderer.runners.contextChange.emit(this.gpu); + }); + return this._initPromise; + } + /** + * Handle the context change event + * @param gpu + */ + contextChange(gpu) { + this._renderer.gpu = gpu; + } + /** + * Helper class to create a WebGL Context + * @param {object} options - An options object that gets passed in to the canvas element containing the + * context attributes + * @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext + * @returns {WebGLRenderingContext} the WebGL context + */ + async _createDeviceAndAdaptor(options) { + const adapter = await navigator.gpu.requestAdapter({ + powerPreference: options.powerPreference, + forceFallbackAdapter: options.forceFallbackAdapter + }); + const requiredFeatures = [ + "texture-compression-bc", + "texture-compression-astc", + "texture-compression-etc2" + ].filter((feature) => adapter.features.has(feature)); + const device = await adapter.requestDevice({ + requiredFeatures + }); + return { adapter, device }; + } + destroy() { + this.gpu = null; + this._renderer = null; + } + } + /** @ignore */ + GpuDeviceSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "device" + }; + /** The default options for the GpuDeviceSystem. */ + GpuDeviceSystem.defaultOptions = { + /** + * {@link WebGPUOptions.powerPreference} + * @default default + */ + powerPreference: void 0, + /** + * Force the use of the fallback adapter + * @default false + */ + forceFallbackAdapter: false + }; + + "use strict"; + var __defProp$8 = Object.defineProperty; + var __getOwnPropSymbols$8 = Object.getOwnPropertySymbols; + var __hasOwnProp$8 = Object.prototype.hasOwnProperty; + var __propIsEnum$8 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$8 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$8.call(b, prop)) + __defNormalProp$8(a, prop, b[prop]); + if (__getOwnPropSymbols$8) + for (var prop of __getOwnPropSymbols$8(b)) { + if (__propIsEnum$8.call(b, prop)) + __defNormalProp$8(a, prop, b[prop]); + } + return a; + }; + class GpuEncoderSystem { + constructor(renderer) { + this._boundBindGroup = /* @__PURE__ */ Object.create(null); + this._boundVertexBuffer = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + } + renderStart() { + this.commandFinished = new Promise((resolve) => { + this._resolveCommandFinished = resolve; + }); + this.commandEncoder = this._renderer.gpu.device.createCommandEncoder(); + } + beginRenderPass(gpuRenderTarget) { + this.endRenderPass(); + this._clearCache(); + this.renderPassEncoder = this.commandEncoder.beginRenderPass(gpuRenderTarget.descriptor); + } + endRenderPass() { + if (this.renderPassEncoder) { + this.renderPassEncoder.end(); + } + this.renderPassEncoder = null; + } + setViewport(viewport) { + this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1); + } + setPipelineFromGeometryProgramAndState(geometry, program, state, topology) { + const pipeline = this._renderer.pipeline.getPipeline(geometry, program, state, topology); + this.setPipeline(pipeline); + } + setPipeline(pipeline) { + if (this._boundPipeline === pipeline) + return; + this._boundPipeline = pipeline; + this.renderPassEncoder.setPipeline(pipeline); + } + _setVertexBuffer(index, buffer) { + if (this._boundVertexBuffer[index] === buffer) + return; + this._boundVertexBuffer[index] = buffer; + this.renderPassEncoder.setVertexBuffer(index, this._renderer.buffer.updateBuffer(buffer)); + } + _setIndexBuffer(buffer) { + if (this._boundIndexBuffer === buffer) + return; + this._boundIndexBuffer = buffer; + const indexFormat = buffer.data.BYTES_PER_ELEMENT === 2 ? "uint16" : "uint32"; + this.renderPassEncoder.setIndexBuffer(this._renderer.buffer.updateBuffer(buffer), indexFormat); + } + resetBindGroup(index) { + this._boundBindGroup[index] = null; + } + setBindGroup(index, bindGroup, program) { + if (this._boundBindGroup[index] === bindGroup) + return; + this._boundBindGroup[index] = bindGroup; + bindGroup._touch(this._renderer.textureGC.count); + const gpuBindGroup = this._renderer.bindGroup.getBindGroup(bindGroup, program, index); + this.renderPassEncoder.setBindGroup(index, gpuBindGroup); + } + setGeometry(geometry) { + for (const i in geometry.attributes) { + const attribute = geometry.attributes[i]; + this._setVertexBuffer(attribute.location, attribute.buffer); + } + if (geometry.indexBuffer) { + this._setIndexBuffer(geometry.indexBuffer); + } + } + _setShaderBindGroups(shader, skipSync) { + for (const i in shader.groups) { + const bindGroup = shader.groups[i]; + if (!skipSync) { + this._syncBindGroup(bindGroup); + } + this.setBindGroup(i, bindGroup, shader.gpuProgram); + } + } + _syncBindGroup(bindGroup) { + for (const j in bindGroup.resources) { + const resource = bindGroup.resources[j]; + if (resource.isUniformGroup) { + this._renderer.ubo.updateUniformGroup(resource); + } + } + } + draw(options) { + const { geometry, shader, state, topology, size, start, instanceCount, skipSync } = options; + this.setPipelineFromGeometryProgramAndState(geometry, shader.gpuProgram, state, topology); + this.setGeometry(geometry); + this._setShaderBindGroups(shader, skipSync); + if (geometry.indexBuffer) { + this.renderPassEncoder.drawIndexed( + size || geometry.indexBuffer.data.length, + instanceCount || geometry.instanceCount, + start || 0 + ); + } else { + this.renderPassEncoder.draw(size || geometry.getSize(), instanceCount || geometry.instanceCount, start || 0); + } + } + finishRenderPass() { + if (this.renderPassEncoder) { + this.renderPassEncoder.end(); + this.renderPassEncoder = null; + } + } + postrender() { + this.finishRenderPass(); + this._gpu.device.queue.submit([this.commandEncoder.finish()]); + this._resolveCommandFinished(); + this.commandEncoder = null; + } + // restores a render pass if finishRenderPass was called + // not optimised as really used for debugging! + // used when we want to stop drawing and log a texture.. + restoreRenderPass() { + const descriptor = this._renderer.renderTarget.adaptor.getDescriptor( + this._renderer.renderTarget.renderTarget, + false, + [0, 0, 0, 1] + ); + this.renderPassEncoder = this.commandEncoder.beginRenderPass(descriptor); + const boundPipeline = this._boundPipeline; + const boundVertexBuffer = __spreadValues$8({}, this._boundVertexBuffer); + const boundIndexBuffer = this._boundIndexBuffer; + const boundBindGroup = __spreadValues$8({}, this._boundBindGroup); + this._clearCache(); + const viewport = this._renderer.renderTarget.viewport; + this.renderPassEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1); + this.setPipeline(boundPipeline); + for (const i in boundVertexBuffer) { + this._setVertexBuffer(i, boundVertexBuffer[i]); + } + for (const i in boundBindGroup) { + this.setBindGroup(i, boundBindGroup[i], null); + } + this._setIndexBuffer(boundIndexBuffer); + } + _clearCache() { + for (let i = 0; i < 16; i++) { + this._boundBindGroup[i] = null; + this._boundVertexBuffer[i] = null; + } + this._boundIndexBuffer = null; + this._boundPipeline = null; + } + destroy() { + this._renderer = null; + this._gpu = null; + this._boundBindGroup = null; + this._boundVertexBuffer = null; + this._boundIndexBuffer = null; + this._boundPipeline = null; + } + contextChange(gpu) { + this._gpu = gpu; + } + } + /** @ignore */ + GpuEncoderSystem.extension = { + type: [ExtensionType.WebGPUSystem], + name: "encoder", + priority: 1 + }; + + "use strict"; + class GpuStencilSystem { + constructor(renderer) { + this._renderTargetStencilState = /* @__PURE__ */ Object.create(null); + this._renderer = renderer; + renderer.renderTarget.onRenderTargetChange.add(this); + } + onRenderTargetChange(renderTarget) { + let stencilState = this._renderTargetStencilState[renderTarget.uid]; + if (!stencilState) { + stencilState = this._renderTargetStencilState[renderTarget.uid] = { + stencilMode: STENCIL_MODES.DISABLED, + stencilReference: 0 + }; + } + this._activeRenderTarget = renderTarget; + this.setStencilMode(stencilState.stencilMode, stencilState.stencilReference); + } + setStencilMode(stencilMode, stencilReference) { + const stencilState = this._renderTargetStencilState[this._activeRenderTarget.uid]; + stencilState.stencilMode = stencilMode; + stencilState.stencilReference = stencilReference; + const renderer = this._renderer; + renderer.pipeline.setStencilMode(stencilMode); + renderer.encoder.renderPassEncoder.setStencilReference(stencilReference); + } + destroy() { + this._renderer.renderTarget.onRenderTargetChange.remove(this); + this._renderer = null; + this._activeRenderTarget = null; + this._renderTargetStencilState = null; + } + } + /** @ignore */ + GpuStencilSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "stencil" + }; + + "use strict"; + const WGSL_ALIGN_SIZE_DATA = { + i32: { align: 4, size: 4 }, + u32: { align: 4, size: 4 }, + f32: { align: 4, size: 4 }, + f16: { align: 2, size: 2 }, + "vec2": { align: 8, size: 8 }, + "vec2": { align: 8, size: 8 }, + "vec2": { align: 8, size: 8 }, + "vec2": { align: 4, size: 4 }, + "vec3": { align: 16, size: 12 }, + "vec3": { align: 16, size: 12 }, + "vec3": { align: 16, size: 12 }, + "vec3": { align: 8, size: 6 }, + "vec4": { align: 16, size: 16 }, + "vec4": { align: 16, size: 16 }, + "vec4": { align: 16, size: 16 }, + "vec4": { align: 8, size: 8 }, + "mat2x2": { align: 8, size: 16 }, + "mat2x2": { align: 4, size: 8 }, + "mat3x2": { align: 8, size: 24 }, + "mat3x2": { align: 4, size: 12 }, + "mat4x2": { align: 8, size: 32 }, + "mat4x2": { align: 4, size: 16 }, + "mat2x3": { align: 16, size: 32 }, + "mat2x3": { align: 8, size: 16 }, + "mat3x3": { align: 16, size: 48 }, + "mat3x3": { align: 8, size: 24 }, + "mat4x3": { align: 16, size: 64 }, + "mat4x3": { align: 8, size: 32 }, + "mat2x4": { align: 16, size: 32 }, + "mat2x4": { align: 8, size: 16 }, + "mat3x4": { align: 16, size: 48 }, + "mat3x4": { align: 8, size: 24 }, + "mat4x4": { align: 16, size: 64 }, + "mat4x4": { align: 8, size: 32 } + }; + function createUboElementsWGSL(uniformData) { + const uboElements = uniformData.map((data) => ({ + data, + offset: 0, + size: 0 + })); + let offset = 0; + for (let i = 0; i < uboElements.length; i++) { + const uboElement = uboElements[i]; + let size = WGSL_ALIGN_SIZE_DATA[uboElement.data.type].size; + const align = WGSL_ALIGN_SIZE_DATA[uboElement.data.type].align; + if (!WGSL_ALIGN_SIZE_DATA[uboElement.data.type]) { + throw new Error(`[Pixi.js] WebGPU UniformBuffer: Unknown type ${uboElement.data.type}`); + } + if (uboElement.data.size > 1) { + size = Math.max(size, align) * uboElement.data.size; + } + offset = Math.ceil(offset / align) * align; + uboElement.size = size; + uboElement.offset = offset; + offset += size; + } + offset = Math.ceil(offset / 16) * 16; + return { uboElements, size: offset }; + } + + "use strict"; + function generateArraySyncWGSL(uboElement, offsetToAdd) { + const { size, align } = WGSL_ALIGN_SIZE_DATA[uboElement.data.type]; + const remainder = (align - size) / 4; + return ` + v = uv.${uboElement.data.name}; + ${offsetToAdd !== 0 ? `offset += ${offsetToAdd};` : ""} + + arrayOffset = offset; + + t = 0; + + for(var i=0; i < ${uboElement.data.size * (size / 4)}; i++) + { + for(var j = 0; j < ${size / 4}; j++) + { + data[arrayOffset++] = v[t++]; + } + ${remainder !== 0 ? `arrayOffset += ${remainder};` : ""} + } + `; + } + + "use strict"; + function createUboSyncFunctionWGSL(uboElements) { + return createUboSyncFunction( + uboElements, + "uboWgsl", + generateArraySyncWGSL, + uboSyncFunctionsWGSL + ); + } + + "use strict"; + class GpuUboSystem extends UboSystem { + constructor() { + super({ + createUboElements: createUboElementsWGSL, + generateUboSync: createUboSyncFunctionWGSL + }); + } + } + /** @ignore */ + GpuUboSystem.extension = { + type: [ExtensionType.WebGPUSystem], + name: "ubo" + }; + + "use strict"; + const minUniformOffsetAlignment = 128; + class GpuUniformBatchPipe { + constructor(renderer) { + this._bindGroupHash = /* @__PURE__ */ Object.create(null); + // number of buffers.. + this._buffers = []; + this._bindGroups = []; + this._bufferResources = []; + this._renderer = renderer; + this._batchBuffer = new UboBatch({ minUniformOffsetAlignment }); + const totalBuffers = 256 / minUniformOffsetAlignment; + for (let i = 0; i < totalBuffers; i++) { + let usage = BufferUsage.UNIFORM | BufferUsage.COPY_DST; + if (i === 0) + usage |= BufferUsage.COPY_SRC; + this._buffers.push(new Buffer({ + data: this._batchBuffer.data, + usage + })); + } + } + renderEnd() { + this._uploadBindGroups(); + this._resetBindGroups(); + } + _resetBindGroups() { + for (const i in this._bindGroupHash) { + this._bindGroupHash[i] = null; + } + this._batchBuffer.clear(); + } + // just works for single bind groups for now + getUniformBindGroup(group, duplicate) { + if (!duplicate && this._bindGroupHash[group.uid]) { + return this._bindGroupHash[group.uid]; + } + this._renderer.ubo.ensureUniformGroup(group); + const data = group.buffer.data; + const offset = this._batchBuffer.addEmptyGroup(data.length); + this._renderer.ubo.syncUniformGroup(group, this._batchBuffer.data, offset / 4); + this._bindGroupHash[group.uid] = this._getBindGroup(offset / minUniformOffsetAlignment); + return this._bindGroupHash[group.uid]; + } + getUboResource(group) { + this._renderer.ubo.updateUniformGroup(group); + const data = group.buffer.data; + const offset = this._batchBuffer.addGroup(data); + return this._getBufferResource(offset / minUniformOffsetAlignment); + } + getArrayBindGroup(data) { + const offset = this._batchBuffer.addGroup(data); + return this._getBindGroup(offset / minUniformOffsetAlignment); + } + getArrayBufferResource(data) { + const offset = this._batchBuffer.addGroup(data); + const index = offset / minUniformOffsetAlignment; + return this._getBufferResource(index); + } + _getBufferResource(index) { + if (!this._bufferResources[index]) { + const buffer = this._buffers[index % 2]; + this._bufferResources[index] = new BufferResource({ + buffer, + offset: (index / 2 | 0) * 256, + size: minUniformOffsetAlignment + }); + } + return this._bufferResources[index]; + } + _getBindGroup(index) { + if (!this._bindGroups[index]) { + const bindGroup = new BindGroup({ + 0: this._getBufferResource(index) + }); + this._bindGroups[index] = bindGroup; + } + return this._bindGroups[index]; + } + _uploadBindGroups() { + const bufferSystem = this._renderer.buffer; + const firstBuffer = this._buffers[0]; + firstBuffer.update(this._batchBuffer.byteIndex); + bufferSystem.updateBuffer(firstBuffer); + const commandEncoder = this._renderer.gpu.device.createCommandEncoder(); + for (let i = 1; i < this._buffers.length; i++) { + const buffer = this._buffers[i]; + commandEncoder.copyBufferToBuffer( + bufferSystem.getGPUBuffer(firstBuffer), + minUniformOffsetAlignment, + bufferSystem.getGPUBuffer(buffer), + 0, + this._batchBuffer.byteIndex + ); + } + this._renderer.gpu.device.queue.submit([commandEncoder.finish()]); + } + destroy() { + for (let i = 0; i < this._bindGroups.length; i++) { + this._bindGroups[i].destroy(); + } + this._bindGroups = null; + this._bindGroupHash = null; + for (let i = 0; i < this._buffers.length; i++) { + this._buffers[i].destroy(); + } + this._buffers = null; + for (let i = 0; i < this._bufferResources.length; i++) { + this._bufferResources[i].destroy(); + } + this._bufferResources = null; + this._batchBuffer.destroy(); + this._bindGroupHash = null; + this._renderer = null; + } + } + /** @ignore */ + GpuUniformBatchPipe.extension = { + type: [ + ExtensionType.WebGPUPipes + ], + name: "uniformBatch" + }; + + "use strict"; + var __defProp$7 = Object.defineProperty; + var __defProps$4 = Object.defineProperties; + var __getOwnPropDescs$4 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$7 = Object.getOwnPropertySymbols; + var __hasOwnProp$7 = Object.prototype.hasOwnProperty; + var __propIsEnum$7 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$7 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$7.call(b, prop)) + __defNormalProp$7(a, prop, b[prop]); + if (__getOwnPropSymbols$7) + for (var prop of __getOwnPropSymbols$7(b)) { + if (__propIsEnum$7.call(b, prop)) + __defNormalProp$7(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$4 = (a, b) => __defProps$4(a, __getOwnPropDescs$4(b)); + const topologyStringToId = { + "point-list": 0, + "line-list": 1, + "line-strip": 2, + "triangle-list": 3, + "triangle-strip": 4 + }; + function getGraphicsStateKey(geometryLayout, shaderKey, state, blendMode, topology) { + return geometryLayout << 24 | shaderKey << 16 | state << 10 | blendMode << 5 | topology; + } + function getGlobalStateKey(stencilStateId, multiSampleCount, colorMask, renderTarget) { + return colorMask << 6 | stencilStateId << 3 | renderTarget << 1 | multiSampleCount; + } + class PipelineSystem { + constructor(renderer) { + this._moduleCache = /* @__PURE__ */ Object.create(null); + this._bufferLayoutsCache = /* @__PURE__ */ Object.create(null); + this._pipeCache = /* @__PURE__ */ Object.create(null); + this._pipeStateCaches = /* @__PURE__ */ Object.create(null); + this._colorMask = 15; + this._multisampleCount = 1; + this._renderer = renderer; + } + contextChange(gpu) { + this._gpu = gpu; + this.setStencilMode(STENCIL_MODES.DISABLED); + this._updatePipeHash(); + } + setMultisampleCount(multisampleCount) { + if (this._multisampleCount === multisampleCount) + return; + this._multisampleCount = multisampleCount; + this._updatePipeHash(); + } + setRenderTarget(renderTarget) { + this._multisampleCount = renderTarget.msaaSamples; + this._depthStencilAttachment = renderTarget.descriptor.depthStencilAttachment ? 1 : 0; + this._updatePipeHash(); + } + setColorMask(colorMask) { + if (this._colorMask === colorMask) + return; + this._colorMask = colorMask; + this._updatePipeHash(); + } + setStencilMode(stencilMode) { + if (this._stencilMode === stencilMode) + return; + this._stencilMode = stencilMode; + this._stencilState = GpuStencilModesToPixi[stencilMode]; + this._updatePipeHash(); + } + setPipeline(geometry, program, state, passEncoder) { + const pipeline = this.getPipeline(geometry, program, state); + passEncoder.setPipeline(pipeline); + } + getPipeline(geometry, program, state, topology) { + if (!geometry._layoutKey) { + ensureAttributes(geometry, program.attributeData); + this._generateBufferKey(geometry); + } + topology = topology || geometry.topology; + const key = getGraphicsStateKey( + geometry._layoutKey, + program._layoutKey, + state.data, + state._blendModeId, + topologyStringToId[topology] + ); + if (this._pipeCache[key]) + return this._pipeCache[key]; + this._pipeCache[key] = this._createPipeline(geometry, program, state, topology); + return this._pipeCache[key]; + } + _createPipeline(geometry, program, state, topology) { + const device = this._gpu.device; + const buffers = this._createVertexBufferLayouts(geometry); + const blendModes = this._renderer.state.getColorTargets(state); + blendModes[0].writeMask = this._stencilMode === STENCIL_MODES.RENDERING_MASK_ADD ? 0 : this._colorMask; + const layout = this._renderer.shader.getProgramData(program).pipeline; + const descriptor = { + // TODO later check if its helpful to create.. + // layout, + vertex: { + module: this._getModule(program.vertex.source), + entryPoint: program.vertex.entryPoint, + // geometry.. + buffers + }, + fragment: { + module: this._getModule(program.fragment.source), + entryPoint: program.fragment.entryPoint, + targets: blendModes + }, + primitive: { + topology, + cullMode: state.cullMode + }, + layout, + multisample: { + count: this._multisampleCount + }, + // depthStencil, + label: `PIXI Pipeline` + }; + if (this._depthStencilAttachment) { + descriptor.depthStencil = __spreadProps$4(__spreadValues$7({}, this._stencilState), { + format: "depth24plus-stencil8", + depthWriteEnabled: state.depthTest, + depthCompare: state.depthTest ? "less" : "always" + }); + } + const pipeline = device.createRenderPipeline(descriptor); + return pipeline; + } + _getModule(code) { + return this._moduleCache[code] || this._createModule(code); + } + _createModule(code) { + const device = this._gpu.device; + this._moduleCache[code] = device.createShaderModule({ + code + }); + return this._moduleCache[code]; + } + _generateBufferKey(geometry) { + const keyGen = []; + let index = 0; + const attributeKeys = Object.keys(geometry.attributes).sort(); + for (let i = 0; i < attributeKeys.length; i++) { + const attribute = geometry.attributes[attributeKeys[i]]; + keyGen[index++] = attribute.location; + keyGen[index++] = attribute.offset; + keyGen[index++] = attribute.format; + keyGen[index++] = attribute.stride; + } + const stringKey = keyGen.join(""); + geometry._layoutKey = createIdFromString(stringKey, "geometry"); + return geometry._layoutKey; + } + _createVertexBufferLayouts(geometry) { + if (this._bufferLayoutsCache[geometry._layoutKey]) { + return this._bufferLayoutsCache[geometry._layoutKey]; + } + const vertexBuffersLayout = []; + geometry.buffers.forEach((buffer) => { + const bufferEntry = { + arrayStride: 0, + stepMode: "vertex", + attributes: [] + }; + const bufferEntryAttributes = bufferEntry.attributes; + for (const i in geometry.attributes) { + const attribute = geometry.attributes[i]; + if (attribute.buffer === buffer) { + bufferEntry.arrayStride = attribute.stride; + bufferEntry.stepMode = attribute.instance ? "instance" : "vertex"; + bufferEntryAttributes.push({ + shaderLocation: attribute.location, + offset: attribute.offset, + format: attribute.format + }); + } + } + if (bufferEntryAttributes.length) { + vertexBuffersLayout.push(bufferEntry); + } + }); + this._bufferLayoutsCache[geometry._layoutKey] = vertexBuffersLayout; + return vertexBuffersLayout; + } + _updatePipeHash() { + const key = getGlobalStateKey( + this._stencilMode, + this._multisampleCount, + this._colorMask, + this._depthStencilAttachment + ); + if (!this._pipeStateCaches[key]) { + this._pipeStateCaches[key] = /* @__PURE__ */ Object.create(null); + } + this._pipeCache = this._pipeStateCaches[key]; + } + destroy() { + this._renderer = null; + this._bufferLayoutsCache = null; + } + } + /** @ignore */ + PipelineSystem.extension = { + type: [ExtensionType.WebGPUSystem], + name: "pipeline" + }; + + "use strict"; + class GpuRenderTarget { + constructor() { + this.contexts = []; + this.msaaTextures = []; + this.msaaSamples = 1; + } + } + + "use strict"; + class GpuRenderTargetAdaptor { + init(renderer, renderTargetSystem) { + this._renderer = renderer; + this._renderTargetSystem = renderTargetSystem; + } + copyToTexture(sourceRenderSurfaceTexture, destinationTexture, originSrc, size, originDest) { + const renderer = this._renderer; + const baseGpuTexture = this._getGpuColorTexture( + sourceRenderSurfaceTexture + ); + const backGpuTexture = renderer.texture.getGpuSource( + destinationTexture.source + ); + renderer.encoder.commandEncoder.copyTextureToTexture( + { + texture: baseGpuTexture, + origin: originSrc + }, + { + texture: backGpuTexture, + origin: originDest + }, + size + ); + return destinationTexture; + } + startRenderPass(renderTarget, clear = true, clearColor, viewport) { + const renderTargetSystem = this._renderTargetSystem; + const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget); + const descriptor = this.getDescriptor(renderTarget, clear, clearColor); + gpuRenderTarget.descriptor = descriptor; + this._renderer.pipeline.setRenderTarget(gpuRenderTarget); + this._renderer.encoder.beginRenderPass(gpuRenderTarget); + this._renderer.encoder.setViewport(viewport); + } + finishRenderPass() { + this._renderer.encoder.endRenderPass(); + } + /** + * returns the gpu texture for the first color texture in the render target + * mainly used by the filter manager to get copy the texture for blending + * @param renderTarget + * @returns a gpu texture + */ + _getGpuColorTexture(renderTarget) { + const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget); + if (gpuRenderTarget.contexts[0]) { + return gpuRenderTarget.contexts[0].getCurrentTexture(); + } + return this._renderer.texture.getGpuSource( + renderTarget.colorTextures[0].source + ); + } + getDescriptor(renderTarget, clear, clearValue) { + if (typeof clear === "boolean") { + clear = clear ? CLEAR.ALL : CLEAR.NONE; + } + const renderTargetSystem = this._renderTargetSystem; + const gpuRenderTarget = renderTargetSystem.getGpuRenderTarget(renderTarget); + const colorAttachments = renderTarget.colorTextures.map( + (texture, i) => { + const context = gpuRenderTarget.contexts[i]; + let view; + let resolveTarget; + if (context) { + const currentTexture = context.getCurrentTexture(); + const canvasTextureView = currentTexture.createView(); + view = canvasTextureView; + } else { + view = this._renderer.texture.getGpuSource(texture).createView({ + mipLevelCount: 1 + }); + } + if (gpuRenderTarget.msaaTextures[i]) { + resolveTarget = view; + view = this._renderer.texture.getTextureView( + gpuRenderTarget.msaaTextures[i] + ); + } + const loadOp = clear & CLEAR.COLOR ? "clear" : "load"; + clearValue != null ? clearValue : clearValue = renderTargetSystem.defaultClearColor; + return { + view, + resolveTarget, + clearValue, + storeOp: "store", + loadOp + }; + } + ); + let depthStencilAttachment; + if ((renderTarget.stencil || renderTarget.depth) && !renderTarget.depthStencilTexture) { + renderTarget.ensureDepthStencilTexture(); + renderTarget.depthStencilTexture.source.sampleCount = gpuRenderTarget.msaa ? 4 : 1; + } + if (renderTarget.depthStencilTexture) { + const stencilLoadOp = clear & CLEAR.STENCIL ? "clear" : "load"; + const depthLoadOp = clear & CLEAR.DEPTH ? "clear" : "load"; + depthStencilAttachment = { + view: this._renderer.texture.getGpuSource(renderTarget.depthStencilTexture.source).createView(), + stencilStoreOp: "store", + stencilLoadOp, + depthClearValue: 1, + depthLoadOp, + depthStoreOp: "store" + }; + } + const descriptor = { + colorAttachments, + depthStencilAttachment + }; + return descriptor; + } + clear(renderTarget, clear = true, clearColor, viewport) { + if (!clear) + return; + const { gpu, encoder } = this._renderer; + const device = gpu.device; + const standAlone = encoder.commandEncoder === null; + if (standAlone) { + const commandEncoder = device.createCommandEncoder(); + const renderPassDescriptor = this.getDescriptor(renderTarget, clear, clearColor); + const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); + passEncoder.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, 0, 1); + passEncoder.end(); + const gpuCommands = commandEncoder.finish(); + device.queue.submit([gpuCommands]); + } else { + this.startRenderPass(renderTarget, clear, clearColor, viewport); + } + } + initGpuRenderTarget(renderTarget) { + renderTarget.isRoot = true; + const gpuRenderTarget = new GpuRenderTarget(); + renderTarget.colorTextures.forEach((colorTexture, i) => { + if (CanvasSource.test(colorTexture.resource)) { + const context = colorTexture.resource.getContext( + "webgpu" + ); + const alphaMode = colorTexture.transparent ? "premultiplied" : "opaque"; + try { + context.configure({ + device: this._renderer.gpu.device, + // eslint-disable-next-line max-len + usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, + format: "bgra8unorm", + alphaMode + }); + } catch (e) { + console.error(e); + } + gpuRenderTarget.contexts[i] = context; + } + gpuRenderTarget.msaa = colorTexture.source.antialias; + if (colorTexture.source.antialias) { + const msaaTexture = new TextureSource({ + width: 0, + height: 0, + sampleCount: 4 + }); + gpuRenderTarget.msaaTextures[i] = msaaTexture; + } + }); + if (gpuRenderTarget.msaa) { + gpuRenderTarget.msaaSamples = 4; + if (renderTarget.depthStencilTexture) { + renderTarget.depthStencilTexture.source.sampleCount = 4; + } + } + return gpuRenderTarget; + } + destroyGpuRenderTarget(gpuRenderTarget) { + gpuRenderTarget.contexts.forEach((context) => { + context.unconfigure(); + }); + gpuRenderTarget.msaaTextures.forEach((texture) => { + texture.destroy(); + }); + gpuRenderTarget.msaaTextures.length = 0; + gpuRenderTarget.contexts.length = 0; + } + ensureDepthStencilTexture(renderTarget) { + const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget); + if (renderTarget.depthStencilTexture && gpuRenderTarget.msaa) { + renderTarget.depthStencilTexture.source.sampleCount = 4; + } + } + resizeGpuRenderTarget(renderTarget) { + const gpuRenderTarget = this._renderTargetSystem.getGpuRenderTarget(renderTarget); + gpuRenderTarget.width = renderTarget.width; + gpuRenderTarget.height = renderTarget.height; + if (gpuRenderTarget.msaa) { + renderTarget.colorTextures.forEach((colorTexture, i) => { + const msaaTexture = gpuRenderTarget.msaaTextures[i]; + msaaTexture == null ? void 0 : msaaTexture.resize( + colorTexture.source.width, + colorTexture.source.height, + colorTexture.source._resolution + ); + }); + } + } + } + + "use strict"; + class GpuRenderTargetSystem extends RenderTargetSystem { + constructor(renderer) { + super(renderer); + this.adaptor = new GpuRenderTargetAdaptor(); + this.adaptor.init(renderer, this); + } + } + /** @ignore */ + GpuRenderTargetSystem.extension = { + type: [ExtensionType.WebGPUSystem], + name: "renderTarget" + }; + + "use strict"; + + "use strict"; + class GpuShaderSystem { + constructor() { + this._gpuProgramData = /* @__PURE__ */ Object.create(null); + } + contextChange(gpu) { + this._gpu = gpu; + } + getProgramData(program) { + return this._gpuProgramData[program._layoutKey] || this._createGPUProgramData(program); + } + _createGPUProgramData(program) { + const device = this._gpu.device; + const bindGroups = program.gpuLayout.map((group) => device.createBindGroupLayout({ entries: group })); + const pipelineLayoutDesc = { bindGroupLayouts: bindGroups }; + this._gpuProgramData[program._layoutKey] = { + bindGroups, + pipeline: device.createPipelineLayout(pipelineLayoutDesc) + }; + return this._gpuProgramData[program._layoutKey]; + } + destroy() { + this._gpu = null; + this._gpuProgramData = null; + } + } + /** @ignore */ + GpuShaderSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "shader" + }; + + "use strict"; + const GpuBlendModesToPixi = {}; + GpuBlendModesToPixi.normal = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + } + }; + GpuBlendModesToPixi.add = { + alpha: { + srcFactor: "src-alpha", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "one", + dstFactor: "one", + operation: "add" + } + }; + GpuBlendModesToPixi.multiply = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "dst", + dstFactor: "one-minus-src-alpha", + operation: "add" + } + }; + GpuBlendModesToPixi.screen = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "one", + dstFactor: "one-minus-src", + operation: "add" + } + }; + GpuBlendModesToPixi.overlay = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "one", + dstFactor: "one-minus-src", + operation: "add" + } + }; + GpuBlendModesToPixi.none = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "zero", + dstFactor: "zero", + operation: "add" + } + }; + GpuBlendModesToPixi["normal-npm"] = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "src-alpha", + dstFactor: "one-minus-src-alpha", + operation: "add" + } + }; + GpuBlendModesToPixi["add-npm"] = { + alpha: { + srcFactor: "one", + dstFactor: "one", + operation: "add" + }, + color: { + srcFactor: "src-alpha", + dstFactor: "one", + operation: "add" + } + }; + GpuBlendModesToPixi["screen-npm"] = { + alpha: { + srcFactor: "one", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "src-alpha", + dstFactor: "one-minus-src", + operation: "add" + } + }; + GpuBlendModesToPixi.erase = { + alpha: { + srcFactor: "zero", + dstFactor: "one-minus-src-alpha", + operation: "add" + }, + color: { + srcFactor: "zero", + dstFactor: "one-minus-src", + operation: "add" + } + }; + + "use strict"; + class GpuStateSystem { + constructor() { + this.defaultState = new State(); + this.defaultState.blend = true; + } + contextChange(gpu) { + this.gpu = gpu; + } + /** + * Gets the blend mode data for the current state + * @param state - The state to get the blend mode from + */ + getColorTargets(state) { + const blend = GpuBlendModesToPixi[state.blendMode] || GpuBlendModesToPixi.normal; + return [ + { + format: "bgra8unorm", + writeMask: 0, + blend + } + ]; + } + destroy() { + this.gpu = null; + } + } + /** @ignore */ + GpuStateSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "state" + }; + + "use strict"; + const gpuUploadBufferImageResource = { + type: "image", + upload(source, gpuTexture, gpu) { + const resource = source.resource; + const total = (source.pixelWidth | 0) * (source.pixelHeight | 0); + const bytesPerPixel = resource.byteLength / total; + gpu.device.queue.writeTexture( + { texture: gpuTexture }, + resource, + { + offset: 0, + rowsPerImage: source.pixelHeight, + bytesPerRow: source.pixelHeight * bytesPerPixel + }, + { + width: source.pixelWidth, + height: source.pixelHeight, + depthOrArrayLayers: 1 + } + ); + } + }; + + "use strict"; + const blockDataMap = { + "bc1-rgba-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 }, + "bc2-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }, + "bc3-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }, + "bc7-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }, + "etc1-rgb-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 }, + "etc2-rgba8unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }, + "astc-4x4-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 } + }; + const defaultBlockData = { blockBytes: 4, blockWidth: 1, blockHeight: 1 }; + const gpuUploadCompressedTextureResource = { + type: "compressed", + upload(source, gpuTexture, gpu) { + let mipWidth = source.pixelWidth; + let mipHeight = source.pixelHeight; + const blockData = blockDataMap[source.format] || defaultBlockData; + for (let i = 0; i < source.resource.length; i++) { + const levelBuffer = source.resource[i]; + const bytesPerRow = Math.ceil(mipWidth / blockData.blockWidth) * blockData.blockBytes; + gpu.device.queue.writeTexture( + { + texture: gpuTexture, + mipLevel: i + }, + levelBuffer, + { + offset: 0, + bytesPerRow + }, + { + width: Math.ceil(mipWidth / blockData.blockWidth) * blockData.blockWidth, + height: Math.ceil(mipHeight / blockData.blockHeight) * blockData.blockHeight, + depthOrArrayLayers: 1 + } + ); + mipWidth = Math.max(mipWidth >> 1, 1); + mipHeight = Math.max(mipHeight >> 1, 1); + } + } + }; + + "use strict"; + const gpuUploadImageResource = { + type: "image", + upload(source, gpuTexture, gpu) { + const resource = source.resource; + if (!resource) + return; + const width = Math.min(gpuTexture.width, source.resourceWidth || source.pixelWidth); + const height = Math.min(gpuTexture.height, source.resourceHeight || source.pixelHeight); + const premultipliedAlpha = source.alphaMode === "premultiply-alpha-on-upload"; + gpu.device.queue.copyExternalImageToTexture( + { source: resource }, + { texture: gpuTexture, premultipliedAlpha }, + { + width, + height + } + ); + } + }; + + "use strict"; + const gpuUploadVideoResource = { + type: "video", + upload(source, gpuTexture, gpu) { + gpuUploadImageResource.upload(source, gpuTexture, gpu); + } + }; + + "use strict"; + class GpuMipmapGenerator { + constructor(device) { + this.device = device; + this.sampler = device.createSampler({ minFilter: "linear" }); + this.pipelines = {}; + } + _getMipmapPipeline(format) { + let pipeline = this.pipelines[format]; + if (!pipeline) { + if (!this.mipmapShaderModule) { + this.mipmapShaderModule = this.device.createShaderModule({ + code: ( + /* wgsl */ + ` + var pos : array, 3> = array, 3>( + vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); + + struct VertexOutput { + @builtin(position) position : vec4, + @location(0) texCoord : vec2, + }; + + @vertex + fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput { + var output : VertexOutput; + output.texCoord = pos[vertexIndex] * vec2(0.5, -0.5) + vec2(0.5); + output.position = vec4(pos[vertexIndex], 0.0, 1.0); + return output; + } + + @group(0) @binding(0) var imgSampler : sampler; + @group(0) @binding(1) var img : texture_2d; + + @fragment + fn fragmentMain(@location(0) texCoord : vec2) -> @location(0) vec4 { + return textureSample(img, imgSampler, texCoord); + } + ` + ) + }); + } + pipeline = this.device.createRenderPipeline({ + layout: "auto", + vertex: { + module: this.mipmapShaderModule, + entryPoint: "vertexMain" + }, + fragment: { + module: this.mipmapShaderModule, + entryPoint: "fragmentMain", + targets: [{ format }] + } + }); + this.pipelines[format] = pipeline; + } + return pipeline; + } + /** + * Generates mipmaps for the given GPUTexture from the data in level 0. + * @param {module:External.GPUTexture} texture - Texture to generate mipmaps for. + * @returns {module:External.GPUTexture} - The originally passed texture + */ + generateMipmap(texture) { + const pipeline = this._getMipmapPipeline(texture.format); + if (texture.dimension === "3d" || texture.dimension === "1d") { + throw new Error("Generating mipmaps for non-2d textures is currently unsupported!"); + } + let mipTexture = texture; + const arrayLayerCount = texture.depthOrArrayLayers || 1; + const renderToSource = texture.usage & GPUTextureUsage.RENDER_ATTACHMENT; + if (!renderToSource) { + const mipTextureDescriptor = { + size: { + width: Math.ceil(texture.width / 2), + height: Math.ceil(texture.height / 2), + depthOrArrayLayers: arrayLayerCount + }, + format: texture.format, + usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, + mipLevelCount: texture.mipLevelCount - 1 + }; + mipTexture = this.device.createTexture(mipTextureDescriptor); + } + const commandEncoder = this.device.createCommandEncoder({}); + const bindGroupLayout = pipeline.getBindGroupLayout(0); + for (let arrayLayer = 0; arrayLayer < arrayLayerCount; ++arrayLayer) { + let srcView = texture.createView({ + baseMipLevel: 0, + mipLevelCount: 1, + dimension: "2d", + baseArrayLayer: arrayLayer, + arrayLayerCount: 1 + }); + let dstMipLevel = renderToSource ? 1 : 0; + for (let i = 1; i < texture.mipLevelCount; ++i) { + const dstView = mipTexture.createView({ + baseMipLevel: dstMipLevel++, + mipLevelCount: 1, + dimension: "2d", + baseArrayLayer: arrayLayer, + arrayLayerCount: 1 + }); + const passEncoder = commandEncoder.beginRenderPass({ + colorAttachments: [{ + view: dstView, + storeOp: "store", + loadOp: "clear", + clearValue: { r: 0, g: 0, b: 0, a: 0 } + }] + }); + const bindGroup = this.device.createBindGroup({ + layout: bindGroupLayout, + entries: [{ + binding: 0, + resource: this.sampler + }, { + binding: 1, + resource: srcView + }] + }); + passEncoder.setPipeline(pipeline); + passEncoder.setBindGroup(0, bindGroup); + passEncoder.draw(3, 1, 0, 0); + passEncoder.end(); + srcView = dstView; + } + } + if (!renderToSource) { + const mipLevelSize = { + width: Math.ceil(texture.width / 2), + height: Math.ceil(texture.height / 2), + depthOrArrayLayers: arrayLayerCount + }; + for (let i = 1; i < texture.mipLevelCount; ++i) { + commandEncoder.copyTextureToTexture({ + texture: mipTexture, + mipLevel: i - 1 + }, { + texture, + mipLevel: i + }, mipLevelSize); + mipLevelSize.width = Math.ceil(mipLevelSize.width / 2); + mipLevelSize.height = Math.ceil(mipLevelSize.height / 2); + } + } + this.device.queue.submit([commandEncoder.finish()]); + if (!renderToSource) { + mipTexture.destroy(); + } + return texture; + } + } + + "use strict"; + class GpuTextureSystem { + constructor(renderer) { + this.managedTextures = []; + this._gpuSources = /* @__PURE__ */ Object.create(null); + this._gpuSamplers = /* @__PURE__ */ Object.create(null); + this._bindGroupHash = /* @__PURE__ */ Object.create(null); + this._textureViewHash = /* @__PURE__ */ Object.create(null); + this._uploads = { + image: gpuUploadImageResource, + buffer: gpuUploadBufferImageResource, + video: gpuUploadVideoResource, + compressed: gpuUploadCompressedTextureResource + }; + this._renderer = renderer; + } + contextChange(gpu) { + this._gpu = gpu; + } + initSource(source) { + if (source.autoGenerateMipmaps) { + const biggestDimension = Math.max(source.pixelWidth, source.pixelHeight); + source.mipLevelCount = Math.floor(Math.log2(biggestDimension)) + 1; + } + let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST; + if (source.uploadMethodId !== "compressed") { + usage |= GPUTextureUsage.RENDER_ATTACHMENT; + usage |= GPUTextureUsage.COPY_SRC; + } + const blockData = blockDataMap[source.format] || { blockBytes: 4, blockWidth: 1, blockHeight: 1 }; + const width = Math.ceil(source.pixelWidth / blockData.blockWidth) * blockData.blockWidth; + const height = Math.ceil(source.pixelHeight / blockData.blockHeight) * blockData.blockHeight; + const textureDescriptor = { + label: source.label, + size: { width, height }, + format: source.format, + sampleCount: source.sampleCount, + mipLevelCount: source.mipLevelCount, + dimension: source.dimension, + usage + }; + const gpuTexture = this._gpu.device.createTexture(textureDescriptor); + this._gpuSources[source.uid] = gpuTexture; + if (!this.managedTextures.includes(source)) { + source.on("update", this.onSourceUpdate, this); + source.on("resize", this.onSourceResize, this); + source.on("destroy", this.onSourceDestroy, this); + source.on("unload", this.onSourceUnload, this); + source.on("updateMipmaps", this.onUpdateMipmaps, this); + this.managedTextures.push(source); + } + this.onSourceUpdate(source); + return gpuTexture; + } + onSourceUpdate(source) { + const gpuTexture = this.getGpuSource(source); + if (!gpuTexture) + return; + if (this._uploads[source.uploadMethodId]) { + this._uploads[source.uploadMethodId].upload(source, gpuTexture, this._gpu); + } + if (source.autoGenerateMipmaps && source.mipLevelCount > 1) { + this.onUpdateMipmaps(source); + } + } + onSourceUnload(source) { + const gpuTexture = this._gpuSources[source.uid]; + if (gpuTexture) { + this._gpuSources[source.uid] = null; + gpuTexture.destroy(); + } + } + onUpdateMipmaps(source) { + if (!this._mipmapGenerator) { + this._mipmapGenerator = new GpuMipmapGenerator(this._gpu.device); + } + const gpuTexture = this.getGpuSource(source); + this._mipmapGenerator.generateMipmap(gpuTexture); + } + onSourceDestroy(source) { + source.off("update", this.onSourceUpdate, this); + source.off("unload", this.onSourceUnload, this); + source.off("destroy", this.onSourceDestroy, this); + source.off("resize", this.onSourceResize, this); + source.off("updateMipmaps", this.onUpdateMipmaps, this); + this.managedTextures.splice(this.managedTextures.indexOf(source), 1); + this.onSourceUnload(source); + } + onSourceResize(source) { + const gpuTexture = this._gpuSources[source.uid]; + if (!gpuTexture) { + this.initSource(source); + } else if (gpuTexture.width !== source.pixelWidth || gpuTexture.height !== source.pixelHeight) { + this._textureViewHash[source.uid] = null; + this._bindGroupHash[source.uid] = null; + this.onSourceUnload(source); + this.initSource(source); + } + } + _initSampler(sampler) { + this._gpuSamplers[sampler._resourceId] = this._gpu.device.createSampler(sampler); + return this._gpuSamplers[sampler._resourceId]; + } + getGpuSampler(sampler) { + return this._gpuSamplers[sampler._resourceId] || this._initSampler(sampler); + } + getGpuSource(source) { + return this._gpuSources[source.uid] || this.initSource(source); + } + getTextureBindGroup(texture) { + var _a; + return (_a = this._bindGroupHash[texture.uid]) != null ? _a : this._createTextureBindGroup(texture); + } + _createTextureBindGroup(texture) { + const source = texture.source; + const bindGroupId = source.uid; + this._bindGroupHash[bindGroupId] = new BindGroup({ + 0: source, + 1: source.style + }); + return this._bindGroupHash[bindGroupId]; + } + getTextureView(texture) { + var _a; + const source = texture.source; + return (_a = this._textureViewHash[source.uid]) != null ? _a : this._createTextureView(source); + } + _createTextureView(texture) { + this._textureViewHash[texture.uid] = this.getGpuSource(texture).createView(); + return this._textureViewHash[texture.uid]; + } + generateCanvas(texture) { + const renderer = this._renderer; + const commandEncoder = renderer.gpu.device.createCommandEncoder(); + const canvas = DOMAdapter.get().createCanvas(); + canvas.width = texture.source.pixelWidth; + canvas.height = texture.source.pixelHeight; + const context = canvas.getContext("webgpu"); + context.configure({ + device: renderer.gpu.device, + // eslint-disable-next-line max-len + usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC, + format: navigator.gpu.getPreferredCanvasFormat(), + alphaMode: "premultiplied" + }); + commandEncoder.copyTextureToTexture({ + texture: renderer.texture.getGpuSource(texture.source), + origin: { + x: 0, + y: 0 + } + }, { + texture: context.getCurrentTexture() + }, { + width: canvas.width, + height: canvas.height + }); + renderer.gpu.device.queue.submit([commandEncoder.finish()]); + return canvas; + } + getPixels(texture) { + const webGPUCanvas = this.generateCanvas(texture); + const canvasAndContext = CanvasPool.getOptimalCanvasAndContext(webGPUCanvas.width, webGPUCanvas.height); + const context = canvasAndContext.context; + context.drawImage(webGPUCanvas, 0, 0); + const { width, height } = webGPUCanvas; + const imageData = context.getImageData(0, 0, width, height); + const pixels = new Uint8ClampedArray(imageData.data.buffer); + CanvasPool.returnCanvasAndContext(canvasAndContext); + return { pixels, width, height }; + } + destroy() { + this.managedTextures.slice().forEach((source) => this.onSourceDestroy(source)); + this.managedTextures = null; + for (const k of Object.keys(this._bindGroupHash)) { + const key = Number(k); + const bindGroup = this._bindGroupHash[key]; + bindGroup == null ? void 0 : bindGroup.destroy(); + this._bindGroupHash[key] = null; + } + this._gpu = null; + this._mipmapGenerator = null; + this._gpuSources = null; + this._bindGroupHash = null; + this._textureViewHash = null; + this._gpuSamplers = null; + } + } + /** @ignore */ + GpuTextureSystem.extension = { + type: [ + ExtensionType.WebGPUSystem + ], + name: "texture" + }; + + "use strict"; + + "use strict"; + class GpuGraphicsAdaptor { + init() { + const localUniforms = new UniformGroup({ + uTransformMatrix: { value: new Matrix(), type: "mat3x3" }, + uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4" }, + uRound: { value: 0, type: "f32" } + }); + const gpuProgram = compileHighShaderGpuProgram({ + name: "graphics", + bits: [ + colorBit, + generateTextureBatchBit(maxRecommendedTextures()), + localUniformBitGroup2, + roundPixelsBit + ] + }); + this.shader = new Shader({ + gpuProgram, + resources: { + // added on the fly! + localUniforms + } + }); + } + execute(graphicsPipe, renderable) { + const context = renderable.context; + const shader = context.customShader || this.shader; + const renderer = graphicsPipe.renderer; + const contextSystem = renderer.graphicsContext; + const { + geometry, + instructions + } = contextSystem.getContextRenderData(context); + const encoder = renderer.encoder; + encoder.setPipelineFromGeometryProgramAndState( + geometry, + shader.gpuProgram, + graphicsPipe.state + ); + encoder.setGeometry(geometry); + const globalUniformsBindGroup = renderer.globalUniforms.bindGroup; + encoder.setBindGroup(0, globalUniformsBindGroup, shader.gpuProgram); + const localBindGroup = renderer.renderPipes.uniformBatch.getUniformBindGroup(shader.resources.localUniforms, true); + encoder.setBindGroup(2, localBindGroup, shader.gpuProgram); + const batches = instructions.instructions; + for (let i = 0; i < instructions.instructionSize; i++) { + const batch = batches[i]; + shader.groups[1] = batch.bindGroup; + if (!batch.gpuBindGroup) { + const textureBatch = batch.textures; + batch.bindGroup = getTextureBatchBindGroup(textureBatch.textures, textureBatch.count); + batch.gpuBindGroup = renderer.bindGroup.getBindGroup( + batch.bindGroup, + shader.gpuProgram, + 1 + ); + } + encoder.setBindGroup(1, batch.bindGroup, shader.gpuProgram); + encoder.renderPassEncoder.drawIndexed(batch.size, 1, batch.start); + } + } + destroy() { + this.shader.destroy(true); + this.shader = null; + } + } + /** @ignore */ + GpuGraphicsAdaptor.extension = { + type: [ + ExtensionType.WebGPUPipesAdaptor + ], + name: "graphics" + }; + + "use strict"; + class GpuMeshAdapter { + init() { + const gpuProgram = compileHighShaderGpuProgram({ + name: "mesh", + bits: [ + localUniformBit, + textureBit, + roundPixelsBit + ] + }); + this._shader = new Shader({ + gpuProgram, + resources: { + uTexture: Texture.EMPTY._source, + uSampler: Texture.EMPTY._source.style, + textureUniforms: { + uTextureMatrix: { type: "mat3x3", value: new Matrix() } + } + } + }); + } + execute(meshPipe, mesh) { + const renderer = meshPipe.renderer; + let shader = mesh._shader; + if (!shader) { + shader = this._shader; + shader.resources.uTexture = mesh.texture.source; + shader.resources.uSampler = mesh.texture.source.style; + shader.resources.textureUniforms.uniforms.uTextureMatrix = mesh.texture.textureMatrix.mapCoord; + } else if (!shader.gpuProgram) { + warn("Mesh shader has no gpuProgram", mesh.shader); + return; + } + const gpuProgram = shader.gpuProgram; + if (gpuProgram.autoAssignGlobalUniforms) { + shader.groups[0] = renderer.globalUniforms.bindGroup; + } + if (gpuProgram.autoAssignLocalUniforms) { + const localUniforms = meshPipe.localUniforms; + shader.groups[1] = renderer.renderPipes.uniformBatch.getUniformBindGroup(localUniforms, true); + } + renderer.encoder.draw({ + geometry: mesh._geometry, + shader, + state: mesh.state + }); + } + destroy() { + this._shader.destroy(true); + this._shader = null; + } + } + /** @ignore */ + GpuMeshAdapter.extension = { + type: [ + ExtensionType.WebGPUPipesAdaptor + ], + name: "mesh" + }; + + "use strict"; + const DefaultWebGPUSystems = [ + ...SharedSystems, + GpuUboSystem, + GpuEncoderSystem, + GpuDeviceSystem, + GpuBufferSystem, + GpuTextureSystem, + GpuRenderTargetSystem, + GpuShaderSystem, + GpuStateSystem, + PipelineSystem, + GpuColorMaskSystem, + GpuStencilSystem, + BindGroupSystem + ]; + const DefaultWebGPUPipes = [...SharedRenderPipes, GpuUniformBatchPipe]; + const DefaultWebGPUAdapters = [GpuBatchAdaptor, GpuMeshAdapter, GpuGraphicsAdaptor]; + const systems = []; + const renderPipes = []; + const renderPipeAdaptors = []; + extensions.handleByNamedList(ExtensionType.WebGPUSystem, systems); + extensions.handleByNamedList(ExtensionType.WebGPUPipes, renderPipes); + extensions.handleByNamedList(ExtensionType.WebGPUPipesAdaptor, renderPipeAdaptors); + extensions.add(...DefaultWebGPUSystems, ...DefaultWebGPUPipes, ...DefaultWebGPUAdapters); + class WebGPURenderer extends AbstractRenderer { + constructor() { + const systemConfig = { + name: "webgpu", + type: RendererType.WEBGPU, + systems, + renderPipes, + renderPipeAdaptors + }; + super(systemConfig); + } + } + + var WebGPURenderer$1 = { + __proto__: null, + WebGPURenderer: WebGPURenderer + }; + + "use strict"; + const DEPRECATED_DRAW_MODES = { + POINTS: "point-list", + LINES: "line-list", + LINE_STRIP: "line-strip", + TRIANGLES: "triangle-list", + TRIANGLE_STRIP: "triangle-strip" + }; + const DRAW_MODES = new Proxy(DEPRECATED_DRAW_MODES, { + get(target, prop) { + deprecation(v8_0_0, `DRAW_MODES.${prop} is deprecated, use '${DEPRECATED_DRAW_MODES[prop]}' instead`); + return target[prop]; + } + }); + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + const fullFrame = new Rectangle(0, 0, 1, 1); + function viewportFromFrame(viewport, source, frame) { + frame || (frame = fullFrame); + const pixelWidth = source.pixelWidth; + const pixelHeight = source.pixelHeight; + viewport.x = frame.x * pixelWidth | 0; + viewport.y = frame.y * pixelHeight | 0; + viewport.width = frame.width * pixelWidth | 0; + viewport.height = frame.height * pixelHeight | 0; + return viewport; + } + + "use strict"; + + "use strict"; + + "use strict"; + var MSAA_QUALITY = /* @__PURE__ */ ((MSAA_QUALITY2) => { + MSAA_QUALITY2[MSAA_QUALITY2["NONE"] = 0] = "NONE"; + MSAA_QUALITY2[MSAA_QUALITY2["LOW"] = 2] = "LOW"; + MSAA_QUALITY2[MSAA_QUALITY2["MEDIUM"] = 4] = "MEDIUM"; + MSAA_QUALITY2[MSAA_QUALITY2["HIGH"] = 8] = "HIGH"; + return MSAA_QUALITY2; + })(MSAA_QUALITY || {}); + var DEPRECATED_WRAP_MODES = /* @__PURE__ */ ((DEPRECATED_WRAP_MODES2) => { + DEPRECATED_WRAP_MODES2["CLAMP"] = "clamp-to-edge"; + DEPRECATED_WRAP_MODES2["REPEAT"] = "repeat"; + DEPRECATED_WRAP_MODES2["MIRRORED_REPEAT"] = "mirror-repeat"; + return DEPRECATED_WRAP_MODES2; + })(DEPRECATED_WRAP_MODES || {}); + const WRAP_MODES = new Proxy(DEPRECATED_WRAP_MODES, { + get(target, prop) { + deprecation(v8_0_0, `DRAW_MODES.${prop} is deprecated, use '${DEPRECATED_WRAP_MODES[prop]}' instead`); + return target[prop]; + } + }); + var DEPRECATED_SCALE_MODES = /* @__PURE__ */ ((DEPRECATED_SCALE_MODES2) => { + DEPRECATED_SCALE_MODES2["NEAREST"] = "nearest"; + DEPRECATED_SCALE_MODES2["LINEAR"] = "linear"; + return DEPRECATED_SCALE_MODES2; + })(DEPRECATED_SCALE_MODES || {}); + const SCALE_MODES = new Proxy(DEPRECATED_SCALE_MODES, { + get(target, prop) { + deprecation(v8_0_0, `DRAW_MODES.${prop} is deprecated, use '${DEPRECATED_SCALE_MODES[prop]}' instead`); + return target[prop]; + } + }); + + "use strict"; + + "use strict"; + class TextureUvs { + constructor() { + this.x0 = 0; + this.y0 = 0; + this.x1 = 1; + this.y1 = 0; + this.x2 = 1; + this.y2 = 1; + this.x3 = 0; + this.y3 = 1; + this.uvsFloat32 = new Float32Array(8); + } + /** + * Sets the texture Uvs based on the given frame information. + * @protected + * @param frame - The frame of the texture + * @param baseFrame - The base frame of the texture + * @param rotate - Rotation of frame, see {@link groupD8} + */ + set(frame, baseFrame, rotate) { + const tw = baseFrame.width; + const th = baseFrame.height; + if (rotate) { + const w2 = frame.width / 2 / tw; + const h2 = frame.height / 2 / th; + const cX = frame.x / tw + w2; + const cY = frame.y / th + h2; + rotate = groupD8.add(rotate, groupD8.NW); + this.x0 = cX + w2 * groupD8.uX(rotate); + this.y0 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + this.x1 = cX + w2 * groupD8.uX(rotate); + this.y1 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + this.x2 = cX + w2 * groupD8.uX(rotate); + this.y2 = cY + h2 * groupD8.uY(rotate); + rotate = groupD8.add(rotate, 2); + this.x3 = cX + w2 * groupD8.uX(rotate); + this.y3 = cY + h2 * groupD8.uY(rotate); + } else { + this.x0 = frame.x / tw; + this.y0 = frame.y / th; + this.x1 = (frame.x + frame.width) / tw; + this.y1 = frame.y / th; + this.x2 = (frame.x + frame.width) / tw; + this.y2 = (frame.y + frame.height) / th; + this.x3 = frame.x / tw; + this.y3 = (frame.y + frame.height) / th; + } + this.uvsFloat32[0] = this.x0; + this.uvsFloat32[1] = this.y0; + this.uvsFloat32[2] = this.x1; + this.uvsFloat32[3] = this.y1; + this.uvsFloat32[4] = this.x2; + this.uvsFloat32[5] = this.y2; + this.uvsFloat32[6] = this.x3; + this.uvsFloat32[7] = this.y3; + } + toString() { + return `[pixi.js/core:TextureUvs x0=${this.x0} y0=${this.y0} x1=${this.x1} y1=${this.y1} x2=${this.x2} y2=${this.y2} x3=${this.x3} y3=${this.y3}]`; + } + } + + "use strict"; + let uidCount = 0; + function generateUID() { + return uidCount++; + } + + "use strict"; + function parseFunctionBody(fn) { + const fnStr = fn.toString(); + const bodyStart = fnStr.indexOf("{"); + const bodyEnd = fnStr.lastIndexOf("}"); + if (bodyStart === -1 || bodyEnd === -1) { + throw new Error("getFunctionBody: No body found in function definition"); + } + return fnStr.slice(bodyStart + 1, bodyEnd).trim(); + } + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + var __defProp$6 = Object.defineProperty; + var __getOwnPropSymbols$6 = Object.getOwnPropertySymbols; + var __hasOwnProp$6 = Object.prototype.hasOwnProperty; + var __propIsEnum$6 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$6 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$6.call(b, prop)) + __defNormalProp$6(a, prop, b[prop]); + if (__getOwnPropSymbols$6) + for (var prop of __getOwnPropSymbols$6(b)) { + if (__propIsEnum$6.call(b, prop)) + __defNormalProp$6(a, prop, b[prop]); + } + return a; + }; + var __objRest$4 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$6.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$6) + for (var prop of __getOwnPropSymbols$6(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$6.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class RenderContainer extends Container { + /** + * @param options - The options for the container. + */ + constructor(options) { + var _b, _c; + if (typeof options === "function") { + options = { render: options }; + } + const _a = options, { render } = _a, rest = __objRest$4(_a, ["render"]); + super(__spreadValues$6({ + label: "RenderContainer" + }, rest)); + this.batched = false; + /** + * The local bounds of the sprite. + * @type {rendering.Bounds} + */ + this.bounds = new Bounds(); + this.canBundle = false; + this.renderPipeId = "customRender"; + if (render) + this.render = render; + this.containsPoint = (_b = options.containsPoint) != null ? _b : () => false; + this.addBounds = (_c = options.addBounds) != null ? _c : () => false; + } + /** + * An overrideable function that can be used to render the object using the current renderer. + * @param _renderer - The current renderer + */ + render(_renderer) { + } + } + + "use strict"; + function updateLocalTransform(lt, container) { + const scale = container._scale; + const pivot = container._pivot; + const position = container._position; + const sx = scale._x; + const sy = scale._y; + const px = pivot._x; + const py = pivot._y; + lt.a = container._cx * sx; + lt.b = container._sx * sx; + lt.c = container._cy * sy; + lt.d = container._sy * sy; + lt.tx = position._x - (px * lt.a + py * lt.c); + lt.ty = position._y - (px * lt.b + py * lt.d); + } + + "use strict"; + function updateWorldTransform(local, parent, world) { + const lta = local.a; + const ltb = local.b; + const ltc = local.c; + const ltd = local.d; + const lttx = local.tx; + const ltty = local.ty; + const pta = parent.a; + const ptb = parent.b; + const ptc = parent.c; + const ptd = parent.d; + world.a = lta * pta + ltb * ptc; + world.b = lta * ptb + ltb * ptd; + world.c = ltc * pta + ltd * ptc; + world.d = ltc * ptb + ltd * ptd; + world.tx = lttx * pta + ltty * ptc + parent.tx; + world.ty = lttx * ptb + ltty * ptd + parent.ty; + } + + "use strict"; + + "use strict"; + + "use strict"; + const buildMap = { + rectangle: buildRectangle, + polygon: buildPolygon, + triangle: buildTriangle, + circle: buildCircle, + ellipse: buildCircle, + roundedRectangle: buildCircle + }; + function buildGeometryFromPath(options) { + if (options instanceof GraphicsPath) { + options = { + path: options, + textureMatrix: null, + out: null + }; + } + const vertices = []; + const uvs = []; + const indices = []; + const shapePath = options.path.shapePath; + const textureMatrix = options.textureMatrix; + shapePath.shapePrimitives.forEach(({ shape, transform: matrix }) => { + const indexOffset = indices.length; + const vertOffset = vertices.length / 2; + const points = []; + const build = buildMap[shape.type]; + build.build(shape, points); + if (matrix) { + transformVertices(points, matrix); + } + build.triangulate(points, vertices, 2, vertOffset, indices, indexOffset); + const uvsOffset = uvs.length / 2; + if (textureMatrix) { + if (matrix) { + textureMatrix.append(matrix.clone().invert()); + } + buildUvs(vertices, 2, vertOffset, uvs, uvsOffset, 2, vertices.length / 2 - vertOffset, textureMatrix); + } else { + buildSimpleUvs(uvs, uvsOffset, 2, vertices.length / 2 - vertOffset); + } + }); + const out = options.out; + if (out) { + out.positions = new Float32Array(vertices); + out.uvs = new Float32Array(uvs); + out.indices = new Uint32Array(indices); + return out; + } + const geometry = new MeshGeometry({ + positions: new Float32Array(vertices), + uvs: new Float32Array(uvs), + indices: new Uint32Array(indices) + }); + return geometry; + } + + "use strict"; + var __defProp$5 = Object.defineProperty; + var __defProps$3 = Object.defineProperties; + var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols; + var __hasOwnProp$5 = Object.prototype.hasOwnProperty; + var __propIsEnum$5 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$5 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$5.call(b, prop)) + __defNormalProp$5(a, prop, b[prop]); + if (__getOwnPropSymbols$5) + for (var prop of __getOwnPropSymbols$5(b)) { + if (__propIsEnum$5.call(b, prop)) + __defNormalProp$5(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b)); + var __objRest$3 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$5.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$5) + for (var prop of __getOwnPropSymbols$5(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$5.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class MeshPlane extends Mesh { + /** + * @param options - Options to be applied to MeshPlane + */ + constructor(options) { + const _a = options, { texture, verticesX, verticesY } = _a, rest = __objRest$3(_a, ["texture", "verticesX", "verticesY"]); + const planeGeometry = new PlaneGeometry(definedProps({ + width: texture.width, + height: texture.height, + verticesX, + verticesY + })); + super(definedProps(__spreadProps$3(__spreadValues$5({}, rest), { geometry: planeGeometry, texture }))); + this.texture = texture; + this.autoResize = true; + } + /** + * Method used for overrides, to do something in case texture frame was changed. + * Meshes based on plane can override it and change more details based on texture. + */ + textureUpdated() { + const geometry = this.geometry; + const { width, height } = this.texture; + if (this.autoResize && (geometry.width !== width || geometry.height !== height)) { + geometry.width = width; + geometry.height = height; + geometry.build({}); + } + } + set texture(value) { + var _a; + (_a = this._texture) == null ? void 0 : _a.off("update", this.textureUpdated, this); + super.texture = value; + value.on("update", this.textureUpdated, this); + this.textureUpdated(); + } + /** The texture of the MeshPlane */ + get texture() { + return this._texture; + } + /** + * Destroys this sprite renderable and optionally its texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well + */ + destroy(options) { + this.texture.off("update", this.textureUpdated, this); + super.destroy(options); + } + } + + "use strict"; + var __defProp$4 = Object.defineProperty; + var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols; + var __hasOwnProp$4 = Object.prototype.hasOwnProperty; + var __propIsEnum$4 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$4 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$4.call(b, prop)) + __defNormalProp$4(a, prop, b[prop]); + if (__getOwnPropSymbols$4) + for (var prop of __getOwnPropSymbols$4(b)) { + if (__propIsEnum$4.call(b, prop)) + __defNormalProp$4(a, prop, b[prop]); + } + return a; + }; + const _RopeGeometry = class _RopeGeometry extends MeshGeometry { + /** + * @param options - Options to be applied to rope geometry + */ + constructor(options) { + const { width, points, textureScale } = __spreadValues$4(__spreadValues$4({}, _RopeGeometry.defaultOptions), options); + super({ + positions: new Float32Array(points.length * 4), + uvs: new Float32Array(points.length * 4), + indices: new Uint32Array((points.length - 1) * 6) + }); + this.points = points; + this._width = width; + this.textureScale = textureScale; + this._build(); + } + /** + * The width (i.e., thickness) of the rope. + * @readonly + */ + get width() { + return this._width; + } + /** Refreshes Rope indices and uvs */ + _build() { + const points = this.points; + if (!points) + return; + const vertexBuffer = this.getBuffer("aPosition"); + const uvBuffer = this.getBuffer("aUV"); + const indexBuffer = this.getIndex(); + if (points.length < 1) { + return; + } + if (vertexBuffer.data.length / 4 !== points.length) { + vertexBuffer.data = new Float32Array(points.length * 4); + uvBuffer.data = new Float32Array(points.length * 4); + indexBuffer.data = new Uint16Array((points.length - 1) * 6); + } + const uvs = uvBuffer.data; + const indices = indexBuffer.data; + uvs[0] = 0; + uvs[1] = 0; + uvs[2] = 0; + uvs[3] = 1; + let amount = 0; + let prev = points[0]; + const textureWidth = this._width * this.textureScale; + const total = points.length; + for (let i = 0; i < total; i++) { + const index = i * 4; + if (this.textureScale > 0) { + const dx = prev.x - points[i].x; + const dy = prev.y - points[i].y; + const distance = Math.sqrt(dx * dx + dy * dy); + prev = points[i]; + amount += distance / textureWidth; + } else { + amount = i / (total - 1); + } + uvs[index] = amount; + uvs[index + 1] = 0; + uvs[index + 2] = amount; + uvs[index + 3] = 1; + } + let indexCount = 0; + for (let i = 0; i < total - 1; i++) { + const index = i * 2; + indices[indexCount++] = index; + indices[indexCount++] = index + 1; + indices[indexCount++] = index + 2; + indices[indexCount++] = index + 2; + indices[indexCount++] = index + 1; + indices[indexCount++] = index + 3; + } + uvBuffer.update(); + indexBuffer.update(); + this.updateVertices(); + } + /** refreshes vertices of Rope mesh */ + updateVertices() { + const points = this.points; + if (points.length < 1) { + return; + } + let lastPoint = points[0]; + let nextPoint; + let perpX = 0; + let perpY = 0; + const vertices = this.buffers[0].data; + const total = points.length; + const halfWidth = this.textureScale > 0 ? this.textureScale * this._width / 2 : this._width / 2; + for (let i = 0; i < total; i++) { + const point = points[i]; + const index = i * 4; + if (i < points.length - 1) { + nextPoint = points[i + 1]; + } else { + nextPoint = point; + } + perpY = -(nextPoint.x - lastPoint.x); + perpX = nextPoint.y - lastPoint.y; + let ratio = (1 - i / (total - 1)) * 10; + if (ratio > 1) { + ratio = 1; + } + const perpLength = Math.sqrt(perpX * perpX + perpY * perpY); + if (perpLength < 1e-6) { + perpX = 0; + perpY = 0; + } else { + perpX /= perpLength; + perpY /= perpLength; + perpX *= halfWidth; + perpY *= halfWidth; + } + vertices[index] = point.x + perpX; + vertices[index + 1] = point.y + perpY; + vertices[index + 2] = point.x - perpX; + vertices[index + 3] = point.y - perpY; + lastPoint = point; + } + this.buffers[0].update(); + } + /** Refreshes Rope indices and uvs */ + update() { + if (this.textureScale > 0) { + this._build(); + } else { + this.updateVertices(); + } + } + }; + /** Default options for RopeGeometry constructor. */ + _RopeGeometry.defaultOptions = { + /** The width (i.e., thickness) of the rope. */ + width: 200, + /** An array of points that determine the rope. */ + points: [], + /** Rope texture scale, if zero then the rope texture is stretched. */ + textureScale: 0 + }; + let RopeGeometry = _RopeGeometry; + + "use strict"; + var __defProp$3 = Object.defineProperty; + var __defProps$2 = Object.defineProperties; + var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols; + var __hasOwnProp$3 = Object.prototype.hasOwnProperty; + var __propIsEnum$3 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$3 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$3.call(b, prop)) + __defNormalProp$3(a, prop, b[prop]); + if (__getOwnPropSymbols$3) + for (var prop of __getOwnPropSymbols$3(b)) { + if (__propIsEnum$3.call(b, prop)) + __defNormalProp$3(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b)); + var __objRest$2 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$3.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$3) + for (var prop of __getOwnPropSymbols$3(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$3.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + const _MeshRope = class _MeshRope extends Mesh { + /** + * Note: The wrap mode of the texture is set to REPEAT if `textureScale` is positive. + * @param options + * @param options.texture - The texture to use on the rope. + * @param options.points - An array of {@link math.Point} objects to construct this rope. + * @param {number} options.textureScale - Optional. Positive values scale rope texture + * keeping its aspect ratio. You can reduce alpha channel artifacts by providing a larger texture + * and downsampling here. If set to zero, texture will be stretched instead. + */ + constructor(options) { + const _a = __spreadValues$3(__spreadValues$3({}, _MeshRope.defaultOptions), options), { texture, points, textureScale } = _a, rest = __objRest$2(_a, ["texture", "points", "textureScale"]); + const ropeGeometry = new RopeGeometry(definedProps({ width: texture.height, points, textureScale })); + if (textureScale > 0) { + texture.source.style.addressMode = "repeat"; + } + super(definedProps(__spreadProps$2(__spreadValues$3({}, rest), { + texture, + geometry: ropeGeometry + }))); + this.autoUpdate = true; + this.onRender = this._render; + } + _render() { + const geometry = this.geometry; + if (this.autoUpdate || geometry._width !== this.texture.height) { + geometry._width = this.texture.height; + geometry.update(); + } + } + }; + _MeshRope.defaultOptions = { + textureScale: 0 + }; + let MeshRope = _MeshRope; + + "use strict"; + var __defProp$2 = Object.defineProperty; + var __defProps$1 = Object.defineProperties; + var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols; + var __hasOwnProp$2 = Object.prototype.hasOwnProperty; + var __propIsEnum$2 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$2 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$2.call(b, prop)) + __defNormalProp$2(a, prop, b[prop]); + if (__getOwnPropSymbols$2) + for (var prop of __getOwnPropSymbols$2(b)) { + if (__propIsEnum$2.call(b, prop)) + __defNormalProp$2(a, prop, b[prop]); + } + return a; + }; + var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b)); + var __objRest$1 = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$2.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$2) + for (var prop of __getOwnPropSymbols$2(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$2.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + class MeshSimple extends Mesh { + /** + * @param options - Options to be used for construction + */ + constructor(options) { + const _a = options, { texture, vertices, uvs, indices, topology } = _a, rest = __objRest$1(_a, ["texture", "vertices", "uvs", "indices", "topology"]); + const geometry = new MeshGeometry(definedProps({ + positions: vertices, + uvs, + indices, + topology + })); + super(definedProps(__spreadProps$1(__spreadValues$2({}, rest), { + texture, + geometry + }))); + this.autoUpdate = true; + this.onRender = this._render; + } + /** + * Collection of vertices data. + * @type {Float32Array} + */ + get vertices() { + return this.geometry.getBuffer("aPosition").data; + } + set vertices(value) { + this.geometry.getBuffer("aPosition").data = value; + } + _render() { + if (this.autoUpdate) { + this.geometry.getBuffer("aPosition").update(); + } + } + } + + "use strict"; + function getTextureDefaultMatrix(texture, out) { + const { width, height } = texture.frame; + out.scale(1 / width, 1 / height); + return out; + } + + "use strict"; + var __defProp$1 = Object.defineProperty; + var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; + var __hasOwnProp$1 = Object.prototype.hasOwnProperty; + var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; + var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues$1 = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp$1.call(b, prop)) + __defNormalProp$1(a, prop, b[prop]); + if (__getOwnPropSymbols$1) + for (var prop of __getOwnPropSymbols$1(b)) { + if (__propIsEnum$1.call(b, prop)) + __defNormalProp$1(a, prop, b[prop]); + } + return a; + }; + var __objRest = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp$1.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols$1) + for (var prop of __getOwnPropSymbols$1(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum$1.call(source, prop)) + target[prop] = source[prop]; + } + return target; + }; + const _NineSliceSprite = class _NineSliceSprite extends Container { + /** + * @param {scene.NineSliceSpriteOptions|Texture} options - Options to use + * @param options.texture - The texture to use on the NineSliceSprite. + * @param options.leftWidth - Width of the left vertical bar (A) + * @param options.topHeight - Height of the top horizontal bar (C) + * @param options.rightWidth - Width of the right vertical bar (B) + * @param options.bottomHeight - Height of the bottom horizontal bar (D) + * @param options.width - Width of the NineSliceSprite, + * setting this will actually modify the vertices and not the UV's of this plane. + * @param options.height - Height of the NineSliceSprite, + * setting this will actually modify the vertices and not UV's of this plane. + */ + constructor(options) { + var _b, _c, _d, _e, _f, _g, _h, _i, _j, _k; + if (options instanceof Texture) { + options = { texture: options }; + } + const _a = options, { + width, + height, + leftWidth, + rightWidth, + topHeight, + bottomHeight, + texture, + roundPixels + } = _a, rest = __objRest(_a, [ + "width", + "height", + "leftWidth", + "rightWidth", + "topHeight", + "bottomHeight", + "texture", + "roundPixels" + ]); + super(__spreadValues$1({ + label: "NineSliceSprite" + }, rest)); + this._roundPixels = 0; + this.renderPipeId = "nineSliceSprite"; + this.batched = true; + this._didSpriteUpdate = true; + this.bounds = { minX: 0, minY: 0, maxX: 0, maxY: 0 }; + this._leftWidth = (_c = leftWidth != null ? leftWidth : (_b = texture == null ? void 0 : texture.defaultBorders) == null ? void 0 : _b.left) != null ? _c : NineSliceGeometry.defaultOptions.leftWidth; + this._topHeight = (_e = topHeight != null ? topHeight : (_d = texture == null ? void 0 : texture.defaultBorders) == null ? void 0 : _d.top) != null ? _e : NineSliceGeometry.defaultOptions.topHeight; + this._rightWidth = (_g = rightWidth != null ? rightWidth : (_f = texture == null ? void 0 : texture.defaultBorders) == null ? void 0 : _f.right) != null ? _g : NineSliceGeometry.defaultOptions.rightWidth; + this._bottomHeight = (_i = bottomHeight != null ? bottomHeight : (_h = texture == null ? void 0 : texture.defaultBorders) == null ? void 0 : _h.bottom) != null ? _i : NineSliceGeometry.defaultOptions.bottomHeight; + this.bounds.maxX = this._width = (_j = width != null ? width : texture.width) != null ? _j : NineSliceGeometry.defaultOptions.width; + this.bounds.maxY = this._height = (_k = height != null ? height : texture.height) != null ? _k : NineSliceGeometry.defaultOptions.height; + this.allowChildren = false; + this.texture = texture != null ? texture : _NineSliceSprite.defaultOptions.texture; + this.roundPixels = roundPixels != null ? roundPixels : false; + } + /** The width of the NineSliceSprite, setting this will actually modify the vertices and UV's of this plane. */ + get width() { + return this._width; + } + set width(value) { + this.bounds.maxX = this._width = value; + this.onViewUpdate(); + } + /** The height of the NineSliceSprite, setting this will actually modify the vertices and UV's of this plane. */ + get height() { + return this._height; + } + set height(value) { + this.bounds.maxY = this._height = value; + this.onViewUpdate(); + } + /** The width of the left column (a) of the NineSliceSprite. */ + get leftWidth() { + return this._leftWidth; + } + set leftWidth(value) { + this._leftWidth = value; + this.onViewUpdate(); + } + /** The width of the right column (b) of the NineSliceSprite. */ + get topHeight() { + return this._topHeight; + } + set topHeight(value) { + this._topHeight = value; + this.onViewUpdate(); + } + /** The width of the right column (b) of the NineSliceSprite. */ + get rightWidth() { + return this._rightWidth; + } + set rightWidth(value) { + this._rightWidth = value; + this.onViewUpdate(); + } + /** The width of the right column (b) of the NineSliceSprite. */ + get bottomHeight() { + return this._bottomHeight; + } + set bottomHeight(value) { + this._bottomHeight = value; + this.onViewUpdate(); + } + /** The texture that the NineSliceSprite is using. */ + get texture() { + return this._texture; + } + set texture(value) { + value || (value = Texture.EMPTY); + const currentTexture = this._texture; + if (currentTexture === value) + return; + if (currentTexture && currentTexture.dynamic) + currentTexture.off("update", this.onViewUpdate, this); + if (value.dynamic) + value.on("update", this.onViewUpdate, this); + this._texture = value; + this.onViewUpdate(); + } + /** + * Whether or not to round the x/y position of the sprite. + * @type {boolean} + */ + get roundPixels() { + return !!this._roundPixels; + } + set roundPixels(value) { + this._roundPixels = value ? 1 : 0; + } + /** The original width of the texture */ + get originalWidth() { + return this._texture.width; + } + /** The original height of the texture */ + get originalHeight() { + return this._texture.height; + } + onViewUpdate() { + this._didChangeId += 1 << 12; + this._didSpriteUpdate = true; + if (this.didViewUpdate) + return; + this.didViewUpdate = true; + const renderGroup = this.renderGroup || this.parentRenderGroup; + if (renderGroup) { + renderGroup.onChildViewUpdate(this); + } + } + /** + * Adds the bounds of this object to the bounds object. + * @param bounds - The output bounds object. + */ + addBounds(bounds) { + const _bounds = this.bounds; + bounds.addFrame(_bounds.minX, _bounds.minY, _bounds.maxX, _bounds.maxY); + } + /** + * Checks if the object contains the given point. + * @param point - The point to check + */ + containsPoint(point) { + const bounds = this.bounds; + if (point.x >= bounds.minX && point.x <= bounds.maxX) { + if (point.y >= bounds.minY && point.y <= bounds.maxY) { + return true; + } + } + return false; + } + /** + * Destroys this sprite renderable and optionally its texture. + * @param options - Options parameter. A boolean will act as if all options + * have been set to that value + * @param {boolean} [options.texture=false] - Should it destroy the current texture of the renderable as well + * @param {boolean} [options.textureSource=false] - Should it destroy the textureSource of the renderable as well + */ + destroy(options) { + super.destroy(options); + const destroyTexture = typeof options === "boolean" ? options : options == null ? void 0 : options.texture; + if (destroyTexture) { + const destroyTextureSource = typeof options === "boolean" ? options : options == null ? void 0 : options.textureSource; + this._texture.destroy(destroyTextureSource); + } + this._texture = null; + this.bounds = null; + } + }; + /** The default options, used to override the initial values of any options passed in the constructor. */ + _NineSliceSprite.defaultOptions = { + /** @default Texture.EMPTY */ + texture: Texture.EMPTY + }; + let NineSliceSprite = _NineSliceSprite; + class NineSlicePlane extends NineSliceSprite { + constructor(...args) { + let options = args[0]; + if (options instanceof Texture) { + deprecation(v8_0_0, "NineSlicePlane now uses the options object {texture, leftWidth, rightWidth, topHeight, bottomHeight}"); + options = { + texture: options, + leftWidth: args[1], + topHeight: args[2], + rightWidth: args[3], + bottomHeight: args[4] + }; + } + deprecation(v8_0_0, "NineSlicePlane is deprecated. Use NineSliceSprite instead."); + super(options); + } + } + + "use strict"; + function ensureTextStyle(renderMode, style) { + if (style instanceof TextStyle || style instanceof HTMLTextStyle) { + return style; + } + return renderMode === "html" ? new HTMLTextStyle(style) : new TextStyle(style); + } + + "use strict"; + + "use strict"; + + "use strict"; + + "use strict"; + const DATA_URI = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;charset=([\w-]+))?(?:;(base64))?,(.*)/i; + + "use strict"; + async function logDebugTexture(texture, renderer, size = 200) { + const base64 = await renderer.extract.base64(texture); + await renderer.encoder.commandFinished; + const width = size; + console.log(`logging texture ${texture.source.width}px ${texture.source.height}px`); + const style = [ + "font-size: 1px;", + `padding: ${width}px ${300}px;`, + `background: url(${base64}) no-repeat;`, + "background-size: contain;" + ].join(" "); + console.log("%c ", style); + } + + "use strict"; + var __defProp = Object.defineProperty; + var __defProps = Object.defineProperties; + var __getOwnPropDescs = Object.getOwnPropertyDescriptors; + var __getOwnPropSymbols = Object.getOwnPropertySymbols; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __propIsEnum = Object.prototype.propertyIsEnumerable; + var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; + }; + var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); + const colors = [ + "#000080", + // Navy Blue + "#228B22", + // Forest Green + "#8B0000", + // Dark Red + "#4169E1", + // Royal Blue + "#008080", + // Teal + "#800000", + // Maroon + "#9400D3", + // Dark Violet + "#FF8C00", + // Dark Orange + "#556B2F", + // Olive Green + "#8B008B" + // Dark Magenta + ]; + let colorTick = 0; + function logScene(container, depth = 0, data = { color: "#000000" }) { + if (container.renderGroup) { + data.color = colors[colorTick++]; + } + let spaces = ""; + for (let i = 0; i < depth; i++) { + spaces += " "; + } + let label = container.label; + if (!label && container instanceof Sprite) { + label = `sprite:${container.texture.label}`; + } + let output = `%c ${spaces}|- ${label} (worldX:${container.worldTransform.tx}, relativeRenderX:${container.relativeGroupTransform.tx}, renderX:${container.groupTransform.tx}, localX:${container.x})`; + if (container.renderGroup) { + output += " (RenderGroup)"; + } + if (container.filters) { + output += "(*filters)"; + } + console.log(output, `color:${data.color}; font-weight:bold;`); + depth++; + for (let i = 0; i < container.children.length; i++) { + const child = container.children[i]; + logScene(child, depth, __spreadValues({}, data)); + } + } + function logRenderGroupScene(renderGroup, depth = 0, data = { index: 0, color: "#000000" }) { + let spaces = ""; + for (let i = 0; i < depth; i++) { + spaces += " "; + } + const output = `%c ${spaces}- ${data.index}: ${renderGroup.root.label} worldX:${renderGroup.worldTransform.tx}`; + console.log(output, `color:${data.color}; font-weight:bold;`); + depth++; + for (let i = 0; i < renderGroup.renderGroupChildren.length; i++) { + const child = renderGroup.renderGroupChildren[i]; + logRenderGroupScene(child, depth, __spreadProps(__spreadValues({}, data), { index: i })); + } + } + + "use strict"; + + "use strict"; + + "use strict"; + + exports.AbstractBitmapFont = AbstractBitmapFont; + exports.AbstractRenderer = AbstractRenderer; + exports.AbstractText = AbstractText; + exports.AccessibilitySystem = AccessibilitySystem; + exports.AlphaFilter = AlphaFilter; + exports.AlphaMask = AlphaMask; + exports.AlphaMaskPipe = AlphaMaskPipe; + exports.AnimatedSprite = AnimatedSprite; + exports.Application = Application; + exports.Assets = Assets; + exports.AssetsClass = AssetsClass; + exports.BLEND_TO_NPM = BLEND_TO_NPM; + exports.BUFFER_TYPE = BUFFER_TYPE; + exports.BackgroundLoader = BackgroundLoader; + exports.BackgroundSystem = BackgroundSystem; + exports.Batch = Batch; + exports.BatchGeometry = BatchGeometry; + exports.BatchTextureArray = BatchTextureArray; + exports.BatchableGraphics = BatchableGraphics; + exports.BatchableMesh = BatchableMesh; + exports.BatchableSprite = BatchableSprite; + exports.Batcher = Batcher; + exports.BatcherPipe = BatcherPipe; + exports.BigPool = BigPool; + exports.BindGroup = BindGroup; + exports.BindGroupSystem = BindGroupSystem; + exports.BitmapFont = BitmapFont; + exports.BitmapFontManager = BitmapFontManager; + exports.BitmapText = BitmapText; + exports.BitmapTextPipe = BitmapTextPipe; + exports.BlendModeFilter = BlendModeFilter; + exports.BlendModePipe = BlendModePipe; + exports.BlurFilter = BlurFilter; + exports.BlurFilterPass = BlurFilterPass; + exports.Bounds = Bounds; + exports.BrowserAdapter = BrowserAdapter; + exports.Buffer = Buffer; + exports.BufferImageSource = BufferImageSource; + exports.BufferResource = BufferResource; + exports.BufferUsage = BufferUsage; + exports.CLEAR = CLEAR; + exports.Cache = Cache; + exports.CanvasPool = CanvasPool; + exports.CanvasPoolClass = CanvasPoolClass; + exports.CanvasSource = CanvasSource; + exports.CanvasTextMetrics = CanvasTextMetrics; + exports.CanvasTextPipe = CanvasTextPipe; + exports.CanvasTextSystem = CanvasTextSystem; + exports.Circle = Circle; + exports.Color = Color; + exports.ColorMask = ColorMask; + exports.ColorMaskPipe = ColorMaskPipe; + exports.ColorMatrixFilter = ColorMatrixFilter; + exports.CompressedSource = CompressedSource; + exports.Container = Container; + exports.Culler = Culler; + exports.CullerPlugin = CullerPlugin; + exports.CustomRenderPipe = CustomRenderPipe; + exports.D3D10_RESOURCE_DIMENSION = D3D10_RESOURCE_DIMENSION; + exports.D3DFMT = D3DFMT; + exports.DATA_URI = DATA_URI; + exports.DDS = DDS; + exports.DEG_TO_RAD = DEG_TO_RAD; + exports.DEPRECATED_SCALE_MODES = DEPRECATED_SCALE_MODES; + exports.DEPRECATED_WRAP_MODES = DEPRECATED_WRAP_MODES; + exports.DOMAdapter = DOMAdapter; + exports.DRAW_MODES = DRAW_MODES; + exports.DXGI_FORMAT = DXGI_FORMAT; + exports.DXGI_TO_TEXTURE_FORMAT = DXGI_TO_TEXTURE_FORMAT; + exports.DisplacementFilter = DisplacementFilter; + exports.DynamicBitmapFont = DynamicBitmapFont; + exports.Ellipse = Ellipse; + exports.EventBoundary = EventBoundary; + exports.EventEmitter = EventEmitter; + exports.EventSystem = EventSystem; + exports.EventsTicker = EventsTicker; + exports.ExtensionType = ExtensionType; + exports.ExtractSystem = ExtractSystem; + exports.FOURCC_TO_TEXTURE_FORMAT = FOURCC_TO_TEXTURE_FORMAT; + exports.FederatedContainer = FederatedContainer; + exports.FederatedEvent = FederatedEvent; + exports.FederatedMouseEvent = FederatedMouseEvent; + exports.FederatedPointerEvent = FederatedPointerEvent; + exports.FederatedWheelEvent = FederatedWheelEvent; + exports.FillGradient = FillGradient; + exports.FillPattern = FillPattern; + exports.Filter = Filter; + exports.FilterEffect = FilterEffect; + exports.FilterPipe = FilterPipe; + exports.FilterSystem = FilterSystem; + exports.FontStylePromiseCache = FontStylePromiseCache; + exports.GAUSSIAN_VALUES = GAUSSIAN_VALUES; + exports.GL_FORMATS = GL_FORMATS; + exports.GL_INTERNAL_FORMAT = GL_INTERNAL_FORMAT; + exports.GL_TARGETS = GL_TARGETS; + exports.GL_TYPES = GL_TYPES; + exports.GL_WRAP_MODES = GL_WRAP_MODES; + exports.GenerateTextureSystem = GenerateTextureSystem; + exports.Geometry = Geometry; + exports.GlBackBufferSystem = GlBackBufferSystem; + exports.GlBatchAdaptor = GlBatchAdaptor; + exports.GlBuffer = GlBuffer; + exports.GlBufferSystem = GlBufferSystem; + exports.GlColorMaskSystem = GlColorMaskSystem; + exports.GlContextSystem = GlContextSystem; + exports.GlEncoderSystem = GlEncoderSystem; + exports.GlGeometrySystem = GlGeometrySystem; + exports.GlGraphicsAdaptor = GlGraphicsAdaptor; + exports.GlMeshAdaptor = GlMeshAdaptor; + exports.GlProgram = GlProgram; + exports.GlProgramData = GlProgramData; + exports.GlRenderTarget = GlRenderTarget; + exports.GlRenderTargetAdaptor = GlRenderTargetAdaptor; + exports.GlRenderTargetSystem = GlRenderTargetSystem; + exports.GlShaderSystem = GlShaderSystem; + exports.GlStateSystem = GlStateSystem; + exports.GlStencilSystem = GlStencilSystem; + exports.GlTexture = GlTexture; + exports.GlTextureSystem = GlTextureSystem; + exports.GlUboSystem = GlUboSystem; + exports.GlUniformGroupSystem = GlUniformGroupSystem; + exports.GlobalUniformSystem = GlobalUniformSystem; + exports.GpuBatchAdaptor = GpuBatchAdaptor; + exports.GpuBlendModesToPixi = GpuBlendModesToPixi; + exports.GpuBufferSystem = GpuBufferSystem; + exports.GpuColorMaskSystem = GpuColorMaskSystem; + exports.GpuDeviceSystem = GpuDeviceSystem; + exports.GpuEncoderSystem = GpuEncoderSystem; + exports.GpuGraphicsAdaptor = GpuGraphicsAdaptor; + exports.GpuGraphicsContext = GpuGraphicsContext; + exports.GpuMeshAdapter = GpuMeshAdapter; + exports.GpuMipmapGenerator = GpuMipmapGenerator; + exports.GpuProgram = GpuProgram; + exports.GpuReadBuffer = GpuReadBuffer; + exports.GpuRenderTarget = GpuRenderTarget; + exports.GpuRenderTargetAdaptor = GpuRenderTargetAdaptor; + exports.GpuRenderTargetSystem = GpuRenderTargetSystem; + exports.GpuShaderSystem = GpuShaderSystem; + exports.GpuStateSystem = GpuStateSystem; + exports.GpuStencilModesToPixi = GpuStencilModesToPixi; + exports.GpuStencilSystem = GpuStencilSystem; + exports.GpuTextureSystem = GpuTextureSystem; + exports.GpuUboSystem = GpuUboSystem; + exports.GpuUniformBatchPipe = GpuUniformBatchPipe; + exports.Graphics = Graphics; + exports.GraphicsContext = GraphicsContext; + exports.GraphicsContextRenderData = GraphicsContextRenderData; + exports.GraphicsContextSystem = GraphicsContextSystem; + exports.GraphicsPath = GraphicsPath; + exports.GraphicsPipe = GraphicsPipe; + exports.HTMLText = HTMLText; + exports.HTMLTextPipe = HTMLTextPipe; + exports.HTMLTextRenderData = HTMLTextRenderData; + exports.HTMLTextStyle = HTMLTextStyle; + exports.HTMLTextSystem = HTMLTextSystem; + exports.HelloSystem = HelloSystem; + exports.IGLUniformData = IGLUniformData; + exports.ImageSource = ImageSource; + exports.InstructionSet = InstructionSet; + exports.KTX = KTX; + exports.Loader = Loader; + exports.LoaderParserPriority = LoaderParserPriority; + exports.MSAA_QUALITY = MSAA_QUALITY; + exports.MaskEffectManager = MaskEffectManager; + exports.MaskEffectManagerClass = MaskEffectManagerClass; + exports.MaskFilter = MaskFilter; + exports.Matrix = Matrix; + exports.Mesh = Mesh; + exports.MeshGeometry = MeshGeometry; + exports.MeshPipe = MeshPipe; + exports.MeshPlane = MeshPlane; + exports.MeshRope = MeshRope; + exports.MeshSimple = MeshSimple; + exports.NOOP = NOOP; + exports.NineSliceGeometry = NineSliceGeometry; + exports.NineSlicePlane = NineSlicePlane; + exports.NineSliceSprite = NineSliceSprite; + exports.NineSliceSpritePipe = NineSliceSpritePipe; + exports.NoiseFilter = NoiseFilter; + exports.ObservablePoint = ObservablePoint; + exports.PI_2 = PI_2; + exports.PipelineSystem = PipelineSystem; + exports.PlaneGeometry = PlaneGeometry; + exports.Point = Point; + exports.Polygon = Polygon; + exports.Pool = Pool; + exports.PoolGroupClass = PoolGroupClass; + exports.PrepareBase = PrepareBase; + exports.PrepareQueue = PrepareQueue; + exports.PrepareSystem = PrepareSystem; + exports.PrepareUpload = PrepareUpload; + exports.QuadGeometry = QuadGeometry; + exports.RAD_TO_DEG = RAD_TO_DEG; + exports.Rectangle = Rectangle; + exports.RenderContainer = RenderContainer; + exports.RenderGroup = RenderGroup; + exports.RenderGroupPipe = RenderGroupPipe; + exports.RenderGroupSystem = RenderGroupSystem; + exports.RenderTarget = RenderTarget; + exports.RenderTargetSystem = RenderTargetSystem; + exports.RenderTexture = RenderTexture; + exports.RendererType = RendererType; + exports.ResizePlugin = ResizePlugin; + exports.Resolver = Resolver; + exports.RopeGeometry = RopeGeometry; + exports.RoundedRectangle = RoundedRectangle; + exports.SCALE_MODES = SCALE_MODES; + exports.STENCIL_MODES = STENCIL_MODES; + exports.SVGParser = SVGParser; + exports.SVGToGraphicsPath = SVGToGraphicsPath; + exports.ScissorMask = ScissorMask; + exports.SdfShader = SdfShader; + exports.Shader = Shader; + exports.ShaderStage = ShaderStage; + exports.ShapePath = ShapePath; + exports.SharedRenderPipes = SharedRenderPipes; + exports.SharedSystems = SharedSystems; + exports.Sprite = Sprite; + exports.SpritePipe = SpritePipe; + exports.Spritesheet = Spritesheet; + exports.State = State; + exports.StencilMask = StencilMask; + exports.StencilMaskPipe = StencilMaskPipe; + exports.SystemRunner = SystemRunner; + exports.TEXTURE_FORMAT_BLOCK_SIZE = TEXTURE_FORMAT_BLOCK_SIZE; + exports.Text = Text; + exports.TextStyle = TextStyle; + exports.Texture = Texture; + exports.TextureGCSystem = TextureGCSystem; + exports.TextureMatrix = TextureMatrix; + exports.TexturePool = TexturePool; + exports.TexturePoolClass = TexturePoolClass; + exports.TextureSource = TextureSource; + exports.TextureStyle = TextureStyle; + exports.TextureUvs = TextureUvs; + exports.Ticker = Ticker; + exports.TickerListener = TickerListener; + exports.TickerPlugin = TickerPlugin; + exports.TilingSprite = TilingSprite; + exports.TilingSpritePipe = TilingSpritePipe; + exports.TilingSpriteShader = TilingSpriteShader; + exports.Transform = Transform; + exports.Triangle = Triangle; + exports.UNIFORM_TO_ARRAY_SETTERS = UNIFORM_TO_ARRAY_SETTERS; + exports.UNIFORM_TO_SINGLE_SETTERS = UNIFORM_TO_SINGLE_SETTERS; + exports.UNIFORM_TYPES_MAP = UNIFORM_TYPES_MAP; + exports.UNIFORM_TYPES_VALUES = UNIFORM_TYPES_VALUES; + exports.UPDATE_BLEND = UPDATE_BLEND; + exports.UPDATE_COLOR = UPDATE_COLOR; + exports.UPDATE_PRIORITY = UPDATE_PRIORITY; + exports.UPDATE_TRANSFORM = UPDATE_TRANSFORM; + exports.UPDATE_VISIBLE = UPDATE_VISIBLE; + exports.UboBatch = UboBatch; + exports.UboSystem = UboSystem; + exports.UniformGroup = UniformGroup; + exports.VERSION = VERSION; + exports.VideoSource = VideoSource; + exports.ViewSystem = ViewSystem; + exports.ViewableBuffer = ViewableBuffer; + exports.WGSL_ALIGN_SIZE_DATA = WGSL_ALIGN_SIZE_DATA; + exports.WGSL_TO_STD40_SIZE = WGSL_TO_STD40_SIZE; + exports.WRAP_MODES = WRAP_MODES; + exports.WebGLRenderer = WebGLRenderer; + exports.WebGPURenderer = WebGPURenderer; + exports.WorkerManager = WorkerManager; + exports._getGlobalBounds = _getGlobalBounds; + exports._getGlobalBoundsRecursive = _getGlobalBoundsRecursive; + exports.accessibilityTarget = accessibilityTarget; + exports.addBits = addBits; + exports.addMaskBounds = addMaskBounds; + exports.addMaskLocalBounds = addMaskLocalBounds; + exports.addProgramDefines = addProgramDefines; + exports.alphaFrag = fragment$4; + exports.alphaWgsl = source$5; + exports.applyMatrix = applyMatrix; + exports.applyStyleParams = applyStyleParams; + exports.assignWithIgnore = assignWithIgnore; + exports.autoDetectEnvironment = autoDetectEnvironment; + exports.autoDetectRenderer = autoDetectRenderer; + exports.autoDetectSource = autoDetectSource; + exports.basisTranscoderUrls = basisTranscoderUrls; + exports.bitmapFontCachePlugin = bitmapFontCachePlugin; + exports.bitmapFontTextParser = bitmapFontTextParser; + exports.bitmapFontXMLParser = bitmapFontXMLParser; + exports.bitmapFontXMLStringParser = bitmapFontXMLStringParser; + exports.blendTemplateFrag = blendTemplateFrag; + exports.blendTemplateVert = blendTemplateVert; + exports.blendTemplateWgsl = blendTemplate; + exports.blockDataMap = blockDataMap; + exports.blurTemplateWgsl = source$4; + exports.boundsPool = boundsPool; + exports.browserExt = browserExt; + exports.buildAdaptiveBezier = buildAdaptiveBezier; + exports.buildAdaptiveQuadratic = buildAdaptiveQuadratic; + exports.buildArc = buildArc; + exports.buildArcTo = buildArcTo; + exports.buildArcToSvg = buildArcToSvg; + exports.buildCircle = buildCircle; + exports.buildContextBatches = buildContextBatches; + exports.buildGeometryFromPath = buildGeometryFromPath; + exports.buildInstructions = buildInstructions; + exports.buildLine = buildLine; + exports.buildPolygon = buildPolygon; + exports.buildRectangle = buildRectangle; + exports.buildSimpleUvs = buildSimpleUvs; + exports.buildTriangle = buildTriangle; + exports.buildUvs = buildUvs; + exports.cacheTextureArray = cacheTextureArray; + exports.calculateProjection = calculateProjection; + exports.checkChildrenDidChange = checkChildrenDidChange; + exports.checkDataUrl = checkDataUrl; + exports.checkExtension = checkExtension; + exports.childrenHelperMixin = childrenHelperMixin; + exports.closePointEps = closePointEps; + exports.collectAllRenderables = collectAllRenderables; + exports.collectRenderGroups = collectRenderGroups; + exports.color32BitToUniform = color32BitToUniform; + exports.colorBit = colorBit; + exports.colorBitGl = colorBitGl; + exports.colorMatrixFilterFrag = fragment$3; + exports.colorMatrixFilterWgsl = source$3; + exports.colorToUniform = colorToUniform; + exports.compareModeToGlCompare = compareModeToGlCompare; + exports.compileHighShader = compileHighShader; + exports.compileHighShaderGl = compileHighShaderGl; + exports.compileHighShaderGlProgram = compileHighShaderGlProgram; + exports.compileHighShaderGpuProgram = compileHighShaderGpuProgram; + exports.compileHooks = compileHooks; + exports.compileInputs = compileInputs; + exports.compileOutputs = compileOutputs; + exports.compileShader = compileShader; + exports.convertFormatIfRequired = convertFormatIfRequired; + exports.convertToList = convertToList; + exports.copySearchParams = copySearchParams; + exports.createIdFromString = createIdFromString; + exports.createLevelBuffers = createLevelBuffers; + exports.createLevelBuffersFromKTX = createLevelBuffersFromKTX; + exports.createStringVariations = createStringVariations; + exports.createTexture = createTexture; + exports.createUboElementsSTD40 = createUboElementsSTD40; + exports.createUboElementsWGSL = createUboElementsWGSL; + exports.createUboSyncFunction = createUboSyncFunction; + exports.createUboSyncFunctionSTD40 = createUboSyncFunctionSTD40; + exports.createUboSyncFunctionWGSL = createUboSyncFunctionWGSL; + exports.crossOrigin = crossOrigin; + exports.cullingMixin = cullingMixin; + exports.curveEps = curveEps; + exports.defaultFilterVert = vertex$2; + exports.defaultValue = defaultValue; + exports.definedProps = definedProps; + exports.deprecation = deprecation; + exports.detectAvif = detectAvif; + exports.detectBasis = detectBasis; + exports.detectCompressed = detectCompressed; + exports.detectDefaults = detectDefaults; + exports.detectMp4 = detectMp4; + exports.detectOgv = detectOgv; + exports.detectVideoAlphaMode = detectVideoAlphaMode; + exports.detectWebm = detectWebm; + exports.detectWebp = detectWebp; + exports.determineCrossOrigin = determineCrossOrigin; + exports.displacementFrag = fragment$2; + exports.displacementVert = vertex$1; + exports.displacementWgsl = source$2; + exports.earcut = earcut$1; + exports.effectsMixin = effectsMixin; + exports.ensureAttributes = ensureAttributes; + exports.ensureIsBuffer = ensureIsBuffer; + exports.ensureOptions = ensureOptions; + exports.ensurePrecision = ensurePrecision; + exports.ensureTextStyle = ensureTextStyle; + exports.executeInstructions = executeInstructions; + exports.extensions = extensions; + exports.extractAttributesFromGlProgram = extractAttributesFromGlProgram; + exports.extractAttributesFromGpuProgram = extractAttributesFromGpuProgram; + exports.extractFontFamilies = extractFontFamilies; + exports.extractStructAndGroups = extractStructAndGroups; + exports.fastCopy = fastCopy; + exports.findHooksRx = findHooksRx; + exports.findMixin = findMixin; + exports.fontStringFromTextStyle = fontStringFromTextStyle; + exports.formatShader = formatShader; + exports.fragmentGPUTemplate = fragmentGPUTemplate; + exports.fragmentGlTemplate = fragmentGlTemplate; + exports.generateArraySyncSTD40 = generateArraySyncSTD40; + exports.generateArraySyncWGSL = generateArraySyncWGSL; + exports.generateBlurFragSource = generateBlurFragSource; + exports.generateBlurGlProgram = generateBlurGlProgram; + exports.generateBlurProgram = generateBlurProgram; + exports.generateBlurVertSource = generateBlurVertSource; + exports.generateGPULayout = generateGPULayout; + exports.generateGpuLayoutGroups = generateGpuLayoutGroups; + exports.generateLayout = generateLayout; + exports.generateLayoutHash = generateLayoutHash; + exports.generateProgram = generateProgram; + exports.generateShaderSyncCode = generateShaderSyncCode; + exports.generateTextStyleKey = generateTextStyleKey; + exports.generateTextureBatchBit = generateTextureBatchBit; + exports.generateTextureBatchBitGl = generateTextureBatchBitGl; + exports.generateUID = generateUID; + exports.generateUniformsSync = generateUniformsSync; + exports.getAdjustedBlendModeBlend = getAdjustedBlendModeBlend; + exports.getAttributeInfoFromFormat = getAttributeInfoFromFormat; + exports.getBatchSamplersUniformGroup = getBatchSamplersUniformGroup; + exports.getBitmapTextLayout = getBitmapTextLayout; + exports.getCanvasBoundingBox = getCanvasBoundingBox; + exports.getCanvasFillStyle = getCanvasFillStyle; + exports.getCanvasTexture = getCanvasTexture; + exports.getDefaultUniformValue = getDefaultUniformValue; + exports.getFastGlobalBounds = getFastGlobalBounds; + exports.getFontCss = getFontCss; + exports.getFontFamilyName = getFontFamilyName; + exports.getGeometryBounds = getGeometryBounds; + exports.getGlTypeFromFormat = getGlTypeFromFormat; + exports.getGlobalBounds = getGlobalBounds; + exports.getGlobalRenderableBounds = getGlobalRenderableBounds; + exports.getLocalBounds = getLocalBounds; + exports.getMatrixRelativeToParent = getMatrixRelativeToParent; + exports.getMaxFragmentPrecision = getMaxFragmentPrecision; + exports.getOrientationOfPoints = getOrientationOfPoints; + exports.getParent = getParent; + exports.getPo2TextureFromSource = getPo2TextureFromSource; + exports.getResolutionOfUrl = getResolutionOfUrl; + exports.getSVGUrl = getSVGUrl; + exports.getSupportedCompressedTextureFormats = getSupportedCompressedTextureFormats; + exports.getSupportedGPUCompressedTextureFormats = getSupportedGPUCompressedTextureFormats; + exports.getSupportedGlCompressedTextureFormats = getSupportedGlCompressedTextureFormats; + exports.getSupportedTextureFormats = getSupportedTextureFormats; + exports.getTemporaryCanvasFromImage = getTemporaryCanvasFromImage; + exports.getTestContext = getTestContext; + exports.getTextureBatchBindGroup = getTextureBatchBindGroup; + exports.getTextureDefaultMatrix = getTextureDefaultMatrix; + exports.getTextureFormatFromKTXTexture = getTextureFormatFromKTXTexture; + exports.getUboData = getUboData; + exports.getUniformData = getUniformData; + exports.getUrlExtension = getUrlExtension; + exports.glFormatToGPUFormat = glFormatToGPUFormat; + exports.glUploadBufferImageResource = glUploadBufferImageResource; + exports.glUploadCompressedTextureResource = glUploadCompressedTextureResource; + exports.glUploadImageResource = glUploadImageResource; + exports.glUploadVideoResource = glUploadVideoResource; + exports.globalUniformsBit = globalUniformsBit; + exports.globalUniformsBitGl = globalUniformsBitGl; + exports.globalUniformsUBOBitGl = globalUniformsUBOBitGl; + exports.gpuFormatToBasisTranscoderFormat = gpuFormatToBasisTranscoderFormat; + exports.gpuFormatToKTXBasisTranscoderFormat = gpuFormatToKTXBasisTranscoderFormat; + exports.gpuUploadBufferImageResource = gpuUploadBufferImageResource; + exports.gpuUploadCompressedTextureResource = gpuUploadCompressedTextureResource; + exports.gpuUploadImageResource = gpuUploadImageResource; + exports.gpuUploadVideoResource = gpuUploadVideoResource; + exports.groupD8 = groupD8; + exports.hasCachedCanvasTexture = hasCachedCanvasTexture; + exports.hslWgsl = hsl; + exports.hslgl = hslgl; + exports.hslgpu = hslgpu; + exports.injectBits = injectBits; + exports.insertVersion = insertVersion; + exports.isMobile = isMobile; + exports.isPow2 = isPow2; + exports.isRenderingToScreen = isRenderingToScreen; + exports.isSafari = isSafari; + exports.isSingleItem = isSingleItem; + exports.isWebGLSupported = isWebGLSupported; + exports.isWebGPUSupported = isWebGPUSupported; + exports.ktxTranscoderUrls = ktxTranscoderUrls; + exports.loadBasis = loadBasis; + exports.loadBasisOnWorker = loadBasisOnWorker; + exports.loadBitmapFont = loadBitmapFont; + exports.loadDDS = loadDDS; + exports.loadEnvironmentExtensions = loadEnvironmentExtensions; + exports.loadFontAsBase64 = loadFontAsBase64; + exports.loadFontCSS = loadFontCSS; + exports.loadImageBitmap = loadImageBitmap; + exports.loadJson = loadJson; + exports.loadKTX = loadKTX; + exports.loadKTX2 = loadKTX2; + exports.loadKTX2onWorker = loadKTX2onWorker; + exports.loadSVGImage = loadSVGImage; + exports.loadSvg = loadSvg; + exports.loadTextures = loadTextures; + exports.loadTxt = loadTxt; + exports.loadVideoTextures = loadVideoTextures; + exports.loadWebFont = loadWebFont; + exports.localUniformBit = localUniformBit; + exports.localUniformBitGl = localUniformBitGl; + exports.localUniformBitGroup2 = localUniformBitGroup2; + exports.localUniformMSDFBit = localUniformMSDFBit; + exports.localUniformMSDFBitGl = localUniformMSDFBitGl; + exports.log2 = log2; + exports.logDebugTexture = logDebugTexture; + exports.logProgramError = logProgramError; + exports.logRenderGroupScene = logRenderGroupScene; + exports.logScene = logScene; + exports.mSDFBit = mSDFBit; + exports.mSDFBitGl = mSDFBitGl; + exports.mapFormatToGlFormat = mapFormatToGlFormat; + exports.mapFormatToGlInternalFormat = mapFormatToGlInternalFormat; + exports.mapFormatToGlType = mapFormatToGlType; + exports.mapGlToVertexFormat = mapGlToVertexFormat; + exports.mapSize = mapSize; + exports.mapType = mapType; + exports.mapWebGLBlendModesToPixi = mapWebGLBlendModesToPixi; + exports.maskFrag = fragment; + exports.maskVert = vertex; + exports.maskWgsl = source; + exports.matrixPool = matrixPool; + exports.maxRecommendedTextures = maxRecommendedTextures; + exports.measureHtmlText = measureHtmlText; + exports.measureMixin = measureMixin; + exports.migrateFragmentFromV7toV8 = migrateFragmentFromV7toV8; + exports.mipmapScaleModeToGlFilter = mipmapScaleModeToGlFilter; + exports.mixColors = mixColors; + exports.mixHexColors = mixHexColors; + exports.mixStandardAnd32BitColors = mixStandardAnd32BitColors; + exports.multiplyHexColors = multiplyHexColors; + exports.nextPow2 = nextPow2; + exports.noiseFrag = fragment$1; + exports.noiseWgsl = source$1; + exports.nonCompressedFormats = nonCompressedFormats; + exports.normalizeExtensionPriority = normalizeExtensionPriority; + exports.nssvg = nssvg; + exports.nsxhtml = nsxhtml; + exports.onRenderMixin = onRenderMixin; + exports.parseDDS = parseDDS; + exports.parseFunctionBody = parseFunctionBody; + exports.parseKTX = parseKTX; + exports.path = path; + exports.pointInTriangle = pointInTriangle; + exports.preloadVideo = preloadVideo; + exports.removeItems = removeItems; + exports.removeStructAndGroupDuplicates = removeStructAndGroupDuplicates; + exports.resetUids = resetUids; + exports.resolveCharacters = resolveCharacters; + exports.resolveCompressedTextureUrl = resolveCompressedTextureUrl; + exports.resolveJsonUrl = resolveJsonUrl; + exports.resolveTextureUrl = resolveTextureUrl; + exports.resourceToTexture = resourceToTexture; + exports.roundPixelsBit = roundPixelsBit; + exports.roundPixelsBitGl = roundPixelsBitGl; + exports.roundedShapeArc = roundedShapeArc; + exports.roundedShapeQuadraticCurve = roundedShapeQuadraticCurve; + exports.sayHello = sayHello; + exports.scaleModeToGlFilter = scaleModeToGlFilter; + exports.setBasisTranscoderPath = setBasisTranscoderPath; + exports.setKTXTranscoderPath = setKTXTranscoderPath; + exports.setPositions = setPositions; + exports.setProgramName = setProgramName; + exports.setUvs = setUvs; + exports.sortMixin = sortMixin; + exports.spritesheetAsset = spritesheetAsset; + exports.squaredDistanceToLineSegment = squaredDistanceToLineSegment; + exports.stripVersion = stripVersion; + exports.testImageFormat = testImageFormat; + exports.testVideoFormat = testVideoFormat; + exports.textStyleToCSS = textStyleToCSS; + exports.textureBit = textureBit; + exports.textureBitGl = textureBitGl; + exports.textureFrom = textureFrom; + exports.tilingBit = tilingBit; + exports.tilingBitGl = tilingBitGl; + exports.toFillStyle = toFillStyle; + exports.toLocalGlobalMixin = toLocalGlobalMixin; + exports.toStrokeStyle = toStrokeStyle; + exports.transformVertices = transformVertices; + exports.triangulateWithHoles = triangulateWithHoles; + exports.uboSyncFunctionsSTD40 = uboSyncFunctionsSTD40; + exports.uboSyncFunctionsWGSL = uboSyncFunctionsWGSL; + exports.uid = uid; + exports.uniformParsers = uniformParsers; + exports.unpremultiplyAlpha = unpremultiplyAlpha$1; + exports.unsafeEvalSupported = unsafeEvalSupported; + exports.updateLocalTransform = updateLocalTransform; + exports.updateQuadBounds = updateQuadBounds; + exports.updateRenderGroupTransform = updateRenderGroupTransform; + exports.updateRenderGroupTransforms = updateRenderGroupTransforms; + exports.updateTransformAndChildren = updateTransformAndChildren; + exports.updateTransformBackwards = updateTransformBackwards; + exports.updateWorldTransform = updateWorldTransform; + exports.v8_0_0 = v8_0_0; + exports.validFormats = validFormats; + exports.validateRenderables = validateRenderables; + exports.vertexGPUTemplate = vertexGPUTemplate; + exports.vertexGlTemplate = vertexGlTemplate; + exports.viewportFromFrame = viewportFromFrame; + exports.vkFormatToGPUFormat = vkFormatToGPUFormat; + exports.warn = warn; + exports.wrapModeToGlAddress = wrapModeToGlAddress; + + return exports; + +})({}); +//# sourceMappingURL=pixi.js.map