Files
EMPTYHEAD/node_modules/pixi.js/dist/pixi.js
2025-08-04 18:57:35 +02:00

44115 lines
1.6 MiB

/*!
* PixiJS - v8.4.1
* Compiled Thu, 19 Sep 2024 10:28:58 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$16 = Object.defineProperty;
var __defProps$q = Object.defineProperties;
var __getOwnPropDescs$q = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$16 = Object.getOwnPropertySymbols;
var __hasOwnProp$16 = Object.prototype.hasOwnProperty;
var __propIsEnum$16 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$16 = (obj, key, value) => key in obj ? __defProp$16(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$16 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$16.call(b, prop))
__defNormalProp$16(a, prop, b[prop]);
if (__getOwnPropSymbols$16)
for (var prop of __getOwnPropSymbols$16(b)) {
if (__propIsEnum$16.call(b, prop))
__defNormalProp$16(a, prop, b[prop]);
}
return a;
};
var __spreadProps$q = (a, b) => __defProps$q(a, __getOwnPropDescs$q(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";
ExtensionType2["ShapeBuilder"] = "shape-builder";
ExtensionType2["Batcher"] = "batcher";
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$q(__spreadValues$16({}, metadata), { ref: ext });
}
if (typeof ext === "object") {
ext = __spreadValues$16({}, 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<t.length;n++){var e=t[n][0](r);if(e)return [e,t[n][1]]}return [null,void 0]},x=function(r){return "string"==typeof r?N(r.trim(),y.string):"object"==typeof r&&null!==r?N(r,y.object):[null,void 0]},I=function(r){return x(r)[1]},M=function(r,t){var n=c(r);return {h:n.h,s:e(n.s+100*t,0,100),l:n.l,a:n.a}},H=function(r){return (299*r.r+587*r.g+114*r.b)/1e3/255},$=function(r,t){var n=c(r);return {h:n.h,s:n.s,l:e(n.l+100*t,0,100),a:n.a}},j=function(){function r(r){this.parsed=x(r)[0],this.rgba=this.parsed||{r:0,g:0,b:0,a:1};}return r.prototype.isValid=function(){return null!==this.parsed},r.prototype.brightness=function(){return n(H(this.rgba),2)},r.prototype.isDark=function(){return H(this.rgba)<.5},r.prototype.isLight=function(){return H(this.rgba)>=.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<t&&(t=u,b=g);}return b}};f.string.push([function(f){var r=f.toLowerCase(),d="transparent"===r?"#0000":a[r];return d?new e(d).toRgb():null},"name"]);}
"use strict";
var __defProp$15 = Object.defineProperty;
var __getOwnPropSymbols$15 = Object.getOwnPropertySymbols;
var __hasOwnProp$15 = Object.prototype.hasOwnProperty;
var __propIsEnum$15 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$15 = (obj, key, value) => key in obj ? __defProp$15(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$15 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$15.call(b, prop))
__defNormalProp$15(a, prop, b[prop]);
if (__getOwnPropSymbols$15)
for (var prop of __getOwnPropSymbols$15(b)) {
if (__propIsEnum$15.call(b, prop))
__defNormalProp$15(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._value = this._cloneSource(value);
this._normalize(this._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$15({}, 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 hexadecimal 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 hexadecimal 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$1.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$5.identity();
}
}
const tempMatrix$5 = new Matrix();
const identityMatrix$1 = 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$1(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";
const v8_3_4 = "8.3.4";
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";
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;
}
/** clears the pool - mainly used for debugging! */
clear() {
this._pool.length = 0;
this._index = 0;
}
}
"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<T>} 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<T>} 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<T>} ClassType - The constructor of the items in the pool.
* @returns {Pool<T>} 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";
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;
const renderGroup = this.renderGroup || this.parentRenderGroup;
if (renderGroup) {
renderGroup.structureDidChange = true;
}
this._didContainerChangeTick++;
},
/**
* 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);
},
/**
* Reparent the child to this container, keeping the same worldTransform.
* @param child - The child to reparent
* @returns The first child that was reparented.
* @memberof scene.Container#
*/
reparentChild(...child) {
if (child.length === 1) {
return this.reparentChildAt(child[0], this.children.length);
}
child.forEach((c) => this.reparentChildAt(c, this.children.length));
return child[0];
},
/**
* Reparent the child to this container at the specified index, keeping the same worldTransform.
* @param child - The child to reparent
* @param index - The index to reparent the child to
* @memberof scene.Container#
*/
reparentChildAt(child, index) {
if (child.parent === this) {
this.setChildIndex(child, index);
return child;
}
const childMat = child.worldTransform.clone();
child.removeFromParent();
this.addChildAt(child, index);
const newMatrix = this.worldTransform.clone();
newMatrix.invert();
childMat.prepend(newMatrix);
child.setFromMatrix(childMat);
return child;
}
};
"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 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<Effect>}
*/
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 uid = child.uid;
const didChange = (child._didViewChangeTick & 65535) << 16 | child._didContainerChangeTick & 65535;
const index = previousData.index;
if (previousData.data[index] !== uid || previousData.data[index + 1] !== didChange) {
previousData.data[previousData.index] = uid;
previousData.data[previousData.index + 1] = didChange;
previousData.didChange = true;
}
previousData.index = index + 2;
if (child.children.length) {
checkChildrenDidChange(child, previousData);
}
}
return previousData.didChange;
}
"use strict";
const tempMatrix$4 = 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._didViewChangeTick) {
localBoundsCacheData.didChange = true;
localBoundsCacheData.data[0] = this._didViewChangeTick;
}
checkChildrenDidChange(this, localBoundsCacheData);
if (localBoundsCacheData.didChange) {
getLocalBounds(this, localBoundsCacheData.localBounds, tempMatrix$4);
}
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";
let _tick = 0;
class InstructionSet {
constructor() {
/** a unique id for this instruction set used through the renderer */
this.uid = uid$1("instructionSet");
/** the array of instructions */
this.instructions = [];
/** the actual size of the array (any instructions passed this should be ignored) */
this.instructionSize = 0;
this.renderables = [];
this.tick = 0;
}
/** reset the instruction set so it can be reused set size back to 0 */
reset() {
this.instructionSize = 0;
this.tick = _tick++;
}
/**
* 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() {
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 = [];
}
init(root) {
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]);
}
}
reset() {
this.renderGroupChildren.length = 0;
for (const i in this.childrenToUpdate) {
const childrenAtDepth = this.childrenToUpdate[i];
childrenAtDepth.list.fill(null);
childrenAtDepth.index = 0;
}
this.childrenRenderablesToUpdate.index = 0;
this.childrenRenderablesToUpdate.list.fill(null);
this.root = null;
this.updateTick = 0;
this.structureDidChange = true;
this._onRenderContainers.length = 0;
this.renderGroupParent = null;
}
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();
/** unique id for this container */
this.uid = uid$1("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 = not renderable, 1 = renderable) 0b001
* @internal
* @ignore
*/
this.localDisplayStatus = 7;
// 0b11 | 0b10 | 0b01 | 0b00
/**
* @internal
* @ignore
*/
this.globalDisplayStatus = 7;
/**
* A value that increments each time the containe is modified
* eg children added, removed etc
* @ignore
*/
this._didContainerChangeTick = 0;
/**
* A value that increments each time the container view is modified
* eg texture swap, geometry change etc
* @ignore
*/
this._didViewChangeTick = 0;
/**
* property that tracks if the container transform has changed
* @ignore
*/
this._didLocalTransformChangeId = -1;
this.effects = [];
assignWithIgnore(this, options, {
children: true,
parent: true,
effects: true
});
(_a = options.children) == null ? void 0 : _a.forEach((child) => this.addChild(child));
(_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));
}
/**
* We now use the _didContainerChangeTick and _didViewChangeTick to track changes
* @deprecated since 8.2.6
* @ignore
*/
set _didChangeId(value) {
this._didViewChangeTick = value >> 12 & 4095;
this._didContainerChangeTick = value & 4095;
}
get _didChangeId() {
return this._didContainerChangeTick & 4095 | (this._didViewChangeTick & 4095) << 12;
}
/**
* 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._didViewChangeTick++;
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._didViewChangeTick++;
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._didContainerChangeTick++;
if (this.didChange)
return;
this.didChange = true;
if (this.parentRenderGroup) {
this.parentRenderGroup.onChildUpdate(this);
}
}
set isRenderGroup(value) {
if (!!this.renderGroup === value)
return;
if (value) {
this.enableRenderGroup();
} else {
this.disableRenderGroup();
}
}
/**
* 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;
}
/**
* Calling this enables a render group for this container.
* This means it will be rendered as a separate set of instructions.
* The transform of the container will also be handled on the GPU rather than the CPU.
*/
enableRenderGroup() {
if (this.renderGroup)
return;
const parentRenderGroup = this.parentRenderGroup;
parentRenderGroup == null ? void 0 : parentRenderGroup.removeChild(this);
this.renderGroup = BigPool.get(RenderGroup, this);
this.groupTransform = Matrix.IDENTITY;
parentRenderGroup == null ? void 0 : parentRenderGroup.addChild(this);
this._updateIsSimple();
}
/** This will disable the render group for this container. */
disableRenderGroup() {
if (!this.renderGroup)
return;
const parentRenderGroup = this.parentRenderGroup;
parentRenderGroup == null ? void 0 : parentRenderGroup.removeChild(this);
BigPool.return(this.renderGroup);
this.renderGroup = null;
this.groupTransform = this.relativeGroupTransform;
parentRenderGroup == null ? void 0 : parentRenderGroup.addChild(this);
this._updateIsSimple();
}
/** @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();
if (typeof value === "object") {
height = (_a = value.height) != null ? _a : value.width;
value = value.width;
} else {
height != null ? height : height = value;
}
value !== void 0 && this._setWidth(value, size.width);
height !== void 0 && this._setHeight(height, 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() {
const localTransformChangeId = this._didContainerChangeTick;
if (this._didLocalTransformChangeId === localTransformChangeId)
return;
this._didLocalTransformChangeId = localTransformChangeId;
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 ? 2 : 0;
if ((this.localDisplayStatus & 2) === 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 ? 0 : 4;
if ((this.localDisplayStatus & 4) === 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}</br> title : ${div.title}</br> 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,
pointerType: rootPointerEvent.pointerType,
pointerId: rootPointerEvent.pointerId
}));
}
/**
* 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<type>`, 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;
if (!e.currentTarget.isInteractive()) {
return;
}
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 ("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$14 = Object.defineProperty;
var __getOwnPropSymbols$14 = Object.getOwnPropertySymbols;
var __hasOwnProp$14 = Object.prototype.hasOwnProperty;
var __propIsEnum$14 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$14 = (obj, key, value) => key in obj ? __defProp$14(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$14 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$14.call(b, prop))
__defNormalProp$14(a, prop, b[prop]);
if (__getOwnPropSymbols$14)
for (var prop of __getOwnPropSymbols$14(b)) {
if (__propIsEnum$14.call(b, prop))
__defNormalProp$14(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$14({}, _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$13 = Object.defineProperty;
var __getOwnPropSymbols$13 = Object.getOwnPropertySymbols;
var __hasOwnProp$13 = Object.prototype.hasOwnProperty;
var __propIsEnum$13 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$13 = (obj, key, value) => key in obj ? __defProp$13(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$13 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$13.call(b, prop))
__defNormalProp$13(a, prop, b[prop]);
if (__getOwnPropSymbols$13)
for (var prop of __getOwnPropSymbols$13(b)) {
if (__propIsEnum$13.call(b, prop))
__defNormalProp$13(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$13({ 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$13(__spreadValues$13({}, 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$13(__spreadValues$13({}, 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$13(__spreadValues$13({}, 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$12 = Object.defineProperty;
var __getOwnPropSymbols$12 = Object.getOwnPropertySymbols;
var __hasOwnProp$12 = Object.prototype.hasOwnProperty;
var __propIsEnum$12 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$12 = (obj, key, value) => key in obj ? __defProp$12(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$12 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$12.call(b, prop))
__defNormalProp$12(a, prop, b[prop]);
if (__getOwnPropSymbols$12)
for (var prop of __getOwnPropSymbols$12(b)) {
if (__propIsEnum$12.call(b, prop))
__defNormalProp$12(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$1("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$12(__spreadValues$12({}, _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$11 = Object.defineProperty;
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;
};
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$1("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$1("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$11(__spreadValues$11({}, _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$1("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$1("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$10 = Object.defineProperty;
var __defProps$p = Object.defineProperties;
var __getOwnPropDescs$p = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$10 = Object.getOwnPropertySymbols;
var __hasOwnProp$10 = Object.prototype.hasOwnProperty;
var __propIsEnum$10 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$10 = (obj, key, value) => 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;
};
var __spreadProps$p = (a, b) => __defProps$p(a, __getOwnPropDescs$p(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$p(__spreadValues$10({}, 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 / texBase._resolution;
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] = this.clampOffset / texBase.pixelWidth;
this.uClampOffset[1] = this.clampOffset / 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 {rendering.TextureOptions} options - 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$1("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";
class ViewContainer extends Container {
constructor() {
super(...arguments);
/** @private */
this.canBundle = true;
/** @private */
this.allowChildren = false;
/** @private */
this._roundPixels = 0;
/** @private */
this._lastUsed = 0;
/** @private */
this._lastInstructionTick = -1;
this._bounds = new Bounds(0, 1, 0, 0);
this._boundsDirty = true;
}
/** @private */
_updateBounds() {
}
/**
* 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;
}
/**
* Checks if the object contains the given point.
* @param point - The point to check
*/
containsPoint(point) {
const bounds = this.bounds;
const { x, y } = point;
return x >= bounds.minX && x <= bounds.maxX && y >= bounds.minY && y <= bounds.maxY;
}
destroy(options) {
super.destroy(options);
this._bounds = null;
}
}
"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;
};
var __objRest$k = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$$.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$$)
for (var prop of __getOwnPropSymbols$$(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$$.call(source, prop))
target[prop] = source[prop];
}
return target;
};
class Sprite extends ViewContainer {
/**
* @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$k(_a, ["texture", "anchor", "roundPixels", "width", "height"]);
super(__spreadValues$$({
label: "Sprite"
}, rest));
this.renderPipeId = "sprite";
this.batched = true;
this._didSpriteUpdate = false;
this._sourceBounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 };
this._sourceBoundsDirty = true;
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 !== void 0)
this.width = width;
if (height !== void 0)
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._didViewChangeTick++;
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);
}
/** 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) {
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;
if (typeof value === "object") {
height = (_a = value.height) != null ? _a : value.width;
value = value.width;
} else {
height != null ? height : height = value;
}
value !== void 0 && this._setWidth(value, this._texture.orig.width);
height !== void 0 && this._setHeight(height, 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;
}
/**
* Returns the 2D rendering context for the canvas.
* Caches the context after creating it.
* @returns The 2D rendering context of the canvas.
*/
get context2D() {
return this._context2D || (this._context2D = this.resource.getContext("2d"));
}
}
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.width, options.resource.height);
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 || globalThis.VideoFrame && resource instanceof VideoFrame;
}
}
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$_ = Object.defineProperty;
var __defProps$o = Object.defineProperties;
var __getOwnPropDescs$o = 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$o = (a, b) => __defProps$o(a, __getOwnPropDescs$o(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$_(__spreadValues$_({}, _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<this>} 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;
}
};
_VideoSource.extension = ExtensionType.TextureSource;
/** The default options for video sources. */
_VideoSource.defaultOptions = __spreadProps$o(__spreadValues$_({}, 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 = {}) {
return textureSourceFrom(options);
}
function textureSourceFrom(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: textureSourceFrom(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;
TextureSource.from = textureSourceFrom;
"use strict";
extensions.add(AlphaMask, ColorMask, StencilMask, VideoSource, ImageSource, CanvasSource, BufferImageSource);
"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";
const fragTemplate$1 = [
"precision mediump float;",
"void main(void){",
"float test = 0.1;",
"%forloop%",
"gl_FragColor = vec4(0.0);",
"}"
].join("\n");
function generateIfTestSrc(maxIfs) {
let src = "";
for (let i = 0; i < maxIfs; ++i) {
if (i > 0) {
src += "\nelse ";
}
if (i < maxIfs - 1) {
src += `if(test == ${i}.0){}`;
}
}
return src;
}
function checkMaxIfStatementsInShader(maxIfs, gl) {
if (maxIfs === 0) {
throw new Error("Invalid value of `0` passed to `checkMaxIfStatementsInShader`");
}
const shader = gl.createShader(gl.FRAGMENT_SHADER);
try {
while (true) {
const fragmentSrc = fragTemplate$1.replace(/%forloop%/gi, generateIfTestSrc(maxIfs));
gl.shaderSource(shader, fragmentSrc);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
maxIfs = maxIfs / 2 | 0;
} else {
break;
}
}
} finally {
gl.deleteShader(shader);
}
return maxIfs;
}
"use strict";
let maxTexturesPerBatchCache = null;
function getMaxTexturesPerBatch() {
var _a;
if (maxTexturesPerBatchCache)
return maxTexturesPerBatchCache;
const gl = getTestContext();
maxTexturesPerBatchCache = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
maxTexturesPerBatchCache = checkMaxIfStatementsInShader(
maxTexturesPerBatchCache,
gl
);
(_a = gl.getExtension("WEBGL_lose_context")) == null ? void 0 : _a.loseContext();
return maxTexturesPerBatchCache;
}
"use strict";
const cachedGroups = {};
function getTextureBatchBindGroup(textures, size) {
let uid = 2166136261;
for (let i = 0; i < size; i++) {
uid ^= textures[i].uid;
uid = Math.imul(uid, 16777619);
uid >>>= 0;
}
return cachedGroups[uid] || generateTextureBatchBindGroup(textures, size, uid);
}
let maxTextures = 0;
function generateTextureBatchBindGroup(textures, size, key) {
const bindGroupResources = {};
let bindIndex = 0;
if (!maxTextures)
maxTextures = getMaxTexturesPerBatch();
for (let i = 0; i < maxTextures; i++) {
const texture = i < size ? 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$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;
};
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.textures = new BatchTextureArray();
this.blendMode = "normal";
this.canBundle = true;
}
destroy() {
this.textures = null;
this.gpuBindGroup = null;
this.bindGroup = null;
this.batcher = null;
}
}
const batchPool = [];
let batchPoolIndex = 0;
function getBatchFromPool() {
return batchPoolIndex > 0 ? batchPool[--batchPoolIndex] : new Batch();
}
function returnBatchToPool(batch) {
batchPool[batchPoolIndex++] = batch;
}
let BATCH_TICK = 0;
const _Batcher = class _Batcher {
constructor(options = {}) {
/** unique id for this batcher */
this.uid = uid$1("batcher");
/** Indicates whether the batch data has been modified and needs updating. */
this.dirty = true;
/** The current index of the batch being processed. */
this.batchIndex = 0;
/** An array of all batches created during the current rendering process. */
this.batches = [];
this._elements = [];
var _a;
_Batcher.defaultOptions.maxTextures = (_a = _Batcher.defaultOptions.maxTextures) != null ? _a : getMaxTexturesPerBatch();
options = __spreadValues$Z(__spreadValues$Z({}, _Batcher.defaultOptions), options);
const { maxTextures, attributesInitialSize, indicesInitialSize } = options;
this.attributeBuffer = new ViewableBuffer(attributesInitialSize * 4);
this.indexBuffer = new Uint16Array(indicesInitialSize);
this.maxTextures = maxTextures;
}
begin() {
this.elementSize = 0;
this.elementStart = 0;
this.indexSize = 0;
this.attributeSize = 0;
for (let i = 0; i < this.batchIndex; i++) {
returnBatchToPool(this.batches[i]);
}
this.batchIndex = 0;
this._batchIndexStart = 0;
this._batchIndexSize = 0;
this.dirty = true;
}
add(batchableObject) {
this._elements[this.elementSize++] = batchableObject;
batchableObject._indexStart = this.indexSize;
batchableObject._attributeStart = this.attributeSize;
batchableObject._batcher = this;
this.indexSize += batchableObject.indexSize;
this.attributeSize += batchableObject.attributeSize * 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;
const attributeBuffer = this.attributeBuffer;
if (batchableObject.packAsQuad) {
this.packQuadAttributes(
batchableObject,
attributeBuffer.float32View,
attributeBuffer.uint32View,
batchableObject._attributeStart,
batchableObject._textureId
);
} else {
this.packAttributes(
batchableObject,
attributeBuffer.float32View,
attributeBuffer.uint32View,
batchableObject._attributeStart,
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;
if (!elements[this.elementStart])
return;
let batch = getBatchFromPool();
let textureBatch = batch.textures;
textureBatch.clear();
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 indexBuffer = this.indexBuffer;
let size = this._batchIndexSize;
let start = this._batchIndexStart;
let action = "startBatch";
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 breakRequired = blendMode !== adjustedBlendMode;
if (source._batchTick === BATCH_TICK && !breakRequired) {
element._textureId = source._textureBindLocation;
size += element.indexSize;
if (element.packAsQuad) {
this.packQuadAttributes(
element,
f32,
u32,
element._attributeStart,
element._textureId
);
this.packQuadIndex(
indexBuffer,
element._indexStart,
element._attributeStart / this.vertexSize
);
} else {
this.packAttributes(
element,
f32,
u32,
element._attributeStart,
element._textureId
);
this.packIndex(
element,
indexBuffer,
element._indexStart,
element._attributeStart / this.vertexSize
);
}
element._batch = batch;
continue;
}
source._batchTick = BATCH_TICK;
if (textureBatch.count >= maxTextures || breakRequired) {
this._finishBatch(
batch,
start,
size - start,
textureBatch,
blendMode,
instructionSet,
action
);
action = "renderBatch";
start = size;
blendMode = adjustedBlendMode;
batch = getBatchFromPool();
textureBatch = batch.textures;
textureBatch.clear();
++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;
if (element.packAsQuad) {
this.packQuadAttributes(
element,
f32,
u32,
element._attributeStart,
element._textureId
);
this.packQuadIndex(
indexBuffer,
element._indexStart,
element._attributeStart / this.vertexSize
);
} else {
this.packAttributes(
element,
f32,
u32,
element._attributeStart,
element._textureId
);
this.packIndex(
element,
indexBuffer,
element._indexStart,
element._attributeStart / 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.bindGroup = null;
batch.action = action;
batch.batcher = this;
batch.textures = textureBatch;
batch.blendMode = blendMode;
batch.start = indexStart;
batch.size = indexSize;
++BATCH_TICK;
this.batches[this.batchIndex++] = batch;
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;
}
packQuadIndex(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;
}
packIndex(element, indexBuffer, index, indicesOffset) {
const indices = element.indices;
const size = element.indexSize;
const indexOffset = element.indexOffset;
const attributeOffset = element.attributeOffset;
for (let i = 0; i < size; i++) {
indexBuffer[index++] = indicesOffset + indices[i + indexOffset] - attributeOffset;
}
}
destroy() {
for (let i = 0; i < this.batches.length; i++) {
returnBatchToPool(this.batches[i]);
}
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 = {
maxTextures: null,
attributesInitialSize: 4,
indicesInitialSize: 6
};
let Batcher = _Batcher;
"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 */
this.uid = uid$1("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$1("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$1("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$1("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
},
aUV: {
buffer: attributeBuffer,
format: "float32x2",
stride,
offset: 2 * 4
},
aColor: {
buffer: attributeBuffer,
format: "unorm8x4",
stride,
offset: 4 * 4
},
aTextureIdAndRound: {
buffer: attributeBuffer,
format: "uint16x2",
stride,
offset: 5 * 4
}
},
indexBuffer
});
}
}
"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";
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$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 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$Y(__spreadValues$Y({}, _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<f32>": "float32x2",
"vec3<f32>": "float32x3",
"vec4<f32>": "float32x4",
vec2f: "float32x2",
vec3f: "float32x3",
vec4f: "float32x4",
i32: "sint32",
"vec2<i32>": "sint32x2",
"vec3<i32>": "sint32x3",
"vec4<i32>": "sint32x4",
u32: "uint32",
"vec2<u32>": "uint32x2",
"vec3<u32>": "uint32x3",
"vec4<u32>": "uint32x4",
bool: "uint32",
"vec2<bool>": "uint32x2",
"vec3<bool>": "uint32x3",
"vec4<bool>": "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] === "<uniform>",
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;
/**
* @internal
* @ignore
*/
this._attributeLocationsKey = 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<f32>;
@in aUV: vec2<f32>;
@out @builtin(position) vPosition: vec4<f32>;
@out vUV : vec2<f32>;
@out vColor : vec4<f32>;
{{header}}
struct VSOutput {
{{struct}}
};
@vertex
fn main( {{in}} ) -> VSOutput {
var worldTransformMatrix = globalUniforms.uWorldTransformMatrix;
var modelMatrix = mat3x3<f32>(
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<f32>(1., 1., 1., 1.);
{{main}}
vUV = uv;
var modelViewProjectionMatrix = globalUniforms.uProjectionMatrix * worldTransformMatrix * modelMatrix;
vPosition = vec4<f32>((modelViewProjectionMatrix * vec3<f32>(position, 1.0)).xy, 0.0, 1.0);
vColor *= globalUniforms.uWorldColorAlpha;
{{end}}
{{return}}
};
`
);
const fragmentGPUTemplate = (
/* wgsl */
`
@in vUV : vec2<f32>;
@in vColor : vec4<f32>;
{{header}}
@fragment
fn main(
{{in}}
) -> @location(0) vec4<f32> {
{{start}}
var outColor:vec4<f32>;
{{main}}
var finalColor:vec4<f32> = outColor * vColor;
{{end}}
return finalColor;
};
`
);
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;
{{end}}
}
`
);
"use strict";
const globalUniformsBit = {
name: "global-uniforms-bit",
vertex: {
header: (
/* wgsl */
`
struct GlobalUniforms {
uProjectionMatrix:mat3x3<f32>,
uWorldTransformMatrix:mat3x3<f32>,
uWorldColorAlpha: vec4<f32>,
uResolution: vec2<f32>,
}
@group(0) @binding(0) var<uniform> 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$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;
};
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$X({
name
}, compileHighShaderGl({
template: {
vertex: vertexGlTemplate,
fragment: fragmentGlTemplate
},
bits: [
globalUniformsBitGl,
...bits
]
})));
}
"use strict";
const colorBit = {
name: "color-bit",
vertex: {
header: (
/* wgsl */
`
@in aColor: vec4<f32>;
`
),
main: (
/* wgsl */
`
vColor *= vec4<f32>(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<f32>;");
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<f32>;`);
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<u32>;
@out @interpolate(flat) vTextureId : u32;
`,
main: `
vTextureId = aTextureIdAndRound.y;
`,
end: `
if(aTextureIdAndRound.x == 1)
{
vPosition = vec4<f32>(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw);
}
`
},
fragment: {
header: `
@in @interpolate(flat) vTextureId: u32;
${generateBindingSrc(maxTextures)}
`,
main: `
var uvDx = dpdx(vUV);
var uvDy = dpdy(vUV);
${generateSampleSrc(maxTextures)}
`
}
};
}
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(maxTextures)}
`
}
};
}
return textureBatchBitGlCache[maxTextures];
}
"use strict";
const roundPixelsBit = {
name: "round-pixels-bit",
vertex: {
header: (
/* wgsl */
`
fn roundPixels(position: vec2<f32>, targetSize: vec2<f32>) -> vec2<f32>
{
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 UNIFORM_TYPES_VALUES = [
"f32",
"i32",
"vec2<f32>",
"vec3<f32>",
"vec4<f32>",
"mat2x2<f32>",
"mat3x3<f32>",
"mat4x4<f32>",
"mat3x2<f32>",
"mat4x2<f32>",
"mat2x3<f32>",
"mat4x3<f32>",
"mat2x4<f32>",
"mat3x4<f32>"
];
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<f32>":
return new Float32Array(2 * size);
case "vec3<f32>":
return new Float32Array(3 * size);
case "vec4<f32>":
return new Float32Array(4 * size);
case "mat2x2<f32>":
return new Float32Array([
1,
0,
0,
1
]);
case "mat3x3<f32>":
return new Float32Array([
1,
0,
0,
0,
1,
0,
0,
0,
1
]);
case "mat4x4<f32>":
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$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;
};
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$1("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$1("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$W(__spreadValues$W({}, _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";
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$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$j = (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;
};
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) {
groups = {};
groupMap = {};
if (gpuProgram) {
const groupData = gpuProgram.structsAndGroups.groups;
groupData.forEach((data) => {
groupMap[data.group] = groupMap[data.group] || {};
groupMap[data.group][data.binding] = data.name;
nameHash[data.name] = data;
});
}
let bindTick = 0;
for (const i in resources) {
if (nameHash[i])
continue;
if (!groups[99]) {
groups[99] = new BindGroup();
this._ownedBindGroups.push(groups[99]);
}
nameHash[i] = { group: 99, binding: bindTick, name: i };
groupMap[99] = groupMap[99] || {};
groupMap[99][bindTick] = i;
bindTick++;
}
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$j(_a, ["gpu", "gl"]);
let gpuProgram;
let glProgram;
if (gpu) {
gpuProgram = GpuProgram.from(gpu);
}
if (gl) {
glProgram = GlProgram.from(gl);
}
return new Shader(__spreadValues$V({
gpuProgram,
glProgram
}, rest));
}
}
"use strict";
class DefaultShader extends Shader {
constructor(maxTextures) {
const glProgram = compileHighShaderGlProgram({
name: "batch",
bits: [
colorBitGl,
generateTextureBatchBitGl(maxTextures),
roundPixelsBitGl
]
});
const gpuProgram = compileHighShaderGpuProgram({
name: "batch",
bits: [
colorBit,
generateTextureBatchBit(maxTextures),
roundPixelsBit
]
});
super({
glProgram,
gpuProgram,
resources: {
batchSamplers: getBatchSamplersUniformGroup(maxTextures)
}
});
}
}
"use strict";
let defaultShader = null;
const _DefaultBatcher = class _DefaultBatcher extends Batcher {
constructor() {
super(...arguments);
this.geometry = new BatchGeometry();
this.shader = defaultShader || (defaultShader = new DefaultShader(this.maxTextures));
this.name = _DefaultBatcher.extension.name;
/** The size of one attribute. 1 = 32 bit. x, y, u, v, color, textureIdAndRound -> total = 6 */
this.vertexSize = 6;
}
/**
* Packs the attributes of a DefaultBatchableMeshElement into the provided views.
* @param element - The DefaultBatchableMeshElement to pack.
* @param float32View - The Float32Array view to pack into.
* @param uint32View - The Uint32Array view to pack into.
* @param index - The starting index in the views.
* @param textureId - The texture ID to use.
*/
packAttributes(element, float32View, uint32View, index, textureId) {
const textureIdAndRound = textureId << 16 | element.roundPixels & 65535;
const wt = element.transform;
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, uvs } = element;
const argb = element.color;
const offset = element.attributeOffset;
const end = offset + element.attributeSize;
for (let i = offset; i < end; i++) {
const i2 = i * 2;
const x = positions[i2];
const y = positions[i2 + 1];
float32View[index++] = a * x + c * y + tx;
float32View[index++] = d * y + b * x + ty;
float32View[index++] = uvs[i2];
float32View[index++] = uvs[i2 + 1];
uint32View[index++] = argb;
uint32View[index++] = textureIdAndRound;
}
}
/**
* Packs the attributes of a DefaultBatchableQuadElement into the provided views.
* @param element - The DefaultBatchableQuadElement to pack.
* @param float32View - The Float32Array view to pack into.
* @param uint32View - The Uint32Array view to pack into.
* @param index - The starting index in the views.
* @param textureId - The texture ID to use.
*/
packQuadAttributes(element, float32View, uint32View, index, textureId) {
const texture = element.texture;
const wt = element.transform;
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 = element.bounds;
const w0 = bounds.maxX;
const w1 = bounds.minX;
const h0 = bounds.maxY;
const h1 = bounds.minY;
const uvs = texture.uvs;
const argb = element.color;
const textureIdAndRound = textureId << 16 | element.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;
}
};
/** @ignore */
_DefaultBatcher.extension = {
type: [
ExtensionType.Batcher
],
name: "default"
};
let DefaultBatcher = _DefaultBatcher;
"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";
const identityMatrix = new Matrix();
class BatchableGraphics {
constructor() {
this.packAsQuad = false;
this.batcherName = "default";
this.applyTransform = true;
this.roundPixels = 0;
this._batcher = null;
this._batch = null;
}
get uvs() {
return this.geometryData.uvs;
}
get positions() {
return this.geometryData.vertices;
}
get indices() {
return this.geometryData.indices;
}
get blendMode() {
if (this.applyTransform) {
return this.renderable.groupBlendMode;
}
return "normal";
}
get color() {
const rgb = this.baseColor;
const bgr = rgb >> 16 | rgb & 65280 | (rgb & 255) << 16;
const renderable = this.renderable;
if (renderable) {
return multiplyHexColors(bgr, renderable.groupColor) + (this.alpha * renderable.groupAlpha * 255 << 24);
}
return bgr + (this.alpha * 255 << 24);
}
get transform() {
var _a;
return ((_a = this.renderable) == null ? void 0 : _a.groupTransform) || identityMatrix;
}
copyTo(gpuBuffer) {
gpuBuffer.indexOffset = this.indexOffset;
gpuBuffer.indexSize = this.indexSize;
gpuBuffer.attributeOffset = this.attributeOffset;
gpuBuffer.attributeSize = this.attributeSize;
gpuBuffer.baseColor = this.baseColor;
gpuBuffer.alpha = this.alpha;
gpuBuffer.texture = this.texture;
gpuBuffer.geometryData = this.geometryData;
}
reset() {
this.applyTransform = true;
this.renderable = null;
}
}
"use strict";
var __defProp$U = Object.defineProperty;
var __defProps$n = Object.defineProperties;
var __getOwnPropDescs$n = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$n = (a, b) => __defProps$n(a, __getOwnPropDescs$n(b));
const buildCircle = {
extension: {
type: ExtensionType.ShapeBuilder,
name: "circle"
},
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;
}
};
const buildEllipse = __spreadProps$n(__spreadValues$U({}, buildCircle), { extension: __spreadProps$n(__spreadValues$U({}, buildCircle.extension), { name: "ellipse" }) });
const buildRoundedRectangle = __spreadProps$n(__spreadValues$U({}, buildCircle), { extension: __spreadProps$n(__spreadValues$U({}, buildCircle.extension), { name: "roundedRectangle" }) });
"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 = {
extension: {
type: ExtensionType.ShapeBuilder,
name: "polygon"
},
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 = {
extension: {
type: ExtensionType.ShapeBuilder,
name: "rectangle"
},
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 = {
extension: {
type: ExtensionType.ShapeBuilder,
name: "triangle"
},
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 shapeBuilders = {};
extensions.handleByMap(ExtensionType.ShapeBuilder, shapeBuilders);
extensions.add(buildRectangle, buildPolygon, buildTriangle, buildCircle, buildEllipse, buildRoundedRectangle);
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 = shapeBuilders.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.attributeOffset = vertOffset;
graphicsBatch.attributeSize = vertices.length / 2 - vertOffset;
graphicsBatch.baseColor = 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 = shapeBuilders[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 (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 graphicsBatch = BigPool.get(BatchableGraphics);
graphicsBatch.indexOffset = indexOffset;
graphicsBatch.indexSize = indices.length - indexOffset;
graphicsBatch.attributeOffset = vertOffset;
graphicsBatch.attributeSize = vertices.length / 2 - vertOffset;
graphicsBatch.baseColor = 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 = shapeBuilders[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.batcher = new DefaultBatcher();
this.instructions = new InstructionSet();
}
init() {
this.instructions.reset();
}
/**
* @deprecated since version 8.0.0
* Use `batcher.geometry` instead.
* @see {Batcher#geometry}
*/
get geometry() {
deprecation(v8_3_4, "GraphicsContextRenderData#geometry is deprecated, please use batcher.geometry instead.");
return this.batcher.geometry;
}
}
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._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;
}
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);
}
_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 = graphicsData.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 = batcher.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,
min: 9,
max: 10
};
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._destroyRenderableBound = this.destroyRenderable.bind(this);
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);
}
graphics.off("destroyed", this._destroyRenderableBound);
}
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._destroyRenderableBound);
}
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";
class BatchableMesh {
constructor() {
this.batcherName = "default";
this.packAsQuad = false;
this.indexOffset = 0;
this.attributeOffset = 0;
this.roundPixels = 0;
this._batcher = null;
this._batch = null;
this._uvUpdateId = -1;
this._textureMatrixUpdateId = -1;
}
get blendMode() {
return this.renderable.groupBlendMode;
}
reset() {
this.renderable = null;
this.texture = null;
this._batcher = null;
this._batch = null;
this.geometry = null;
this._uvUpdateId = -1;
this._textureMatrixUpdateId = -1;
}
get uvs() {
const geometry = this.geometry;
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);
}
}
return transformedUvs;
}
get positions() {
return this.geometry.positions;
}
get indices() {
return this.geometry.indices;
}
get color() {
return this.renderable.groupColorAlpha;
}
get groupTransform() {
return this.renderable.groupTransform;
}
get attributeSize() {
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<f32>" },
uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
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._destroyRenderableBound = this.destroyRenderable.bind(this);
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, instructionSet);
} else {
batcher.break(instructionSet);
instructionSet.add(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;
}
mesh.off("destroyed", this._destroyRenderableBound);
}
execute(mesh) {
if (!mesh.isRenderable)
return;
mesh.state.blendMode = getAdjustedBlendModeBlend(mesh.groupBlendMode, mesh.texture._source);
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._destroyRenderableBound);
return this._meshDataHash[mesh.uid];
}
_getBatchableMesh(mesh) {
return this._gpuBatchableMeshHash[mesh.uid] || this._initBatchableMesh(mesh);
}
_initBatchableMesh(mesh) {
const gpuMesh = BigPool.get(BatchableMesh);
gpuMesh.renderable = mesh;
gpuMesh.texture = mesh._texture;
gpuMesh.transform = mesh.groupTransform;
gpuMesh.roundPixels = this.renderer._roundPixels | mesh._roundPixels;
this._gpuBatchableMeshHash[mesh.uid] = gpuMesh;
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() {
this.batcherName = "default";
// batch specific..
this.attributeSize = 4;
this.indexSize = 6;
this.packAsQuad = true;
this.roundPixels = 0;
this._attributeStart = 0;
// location in the buffer
this._batcher = null;
this._batch = null;
}
get blendMode() {
return this.renderable.groupBlendMode;
}
get color() {
return this.renderable.groupColorAlpha;
}
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._destroyRenderableBound = this.destroyRenderable.bind(this);
this._renderer = renderer;
this._renderer.runners.resolutionChange.add(this);
}
resolutionChange() {
for (const i in this._gpuText) {
const gpuText = this._gpuText[i];
if (!gpuText)
continue;
const text = gpuText.batchableSprite.renderable;
if (text._autoResolution) {
text._resolution = this._renderer.resolution;
text.onViewUpdate();
}
}
}
validateRenderable(text) {
const gpuText = this._getGpuText(text);
const newKey = text._getKey();
if (gpuText.currentKey !== newKey) {
const { width, height } = this._renderer.canvasText.getTextureSize(
text.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, instructionSet);
}
updateRenderable(text) {
const gpuText = this._getGpuText(text);
const batchableSprite = gpuText.batchableSprite;
if (text._didTextUpdate) {
this._updateText(text);
}
batchableSprite._batcher.updateElement(batchableSprite);
}
destroyRenderable(text) {
text.off("destroyed", this._destroyRenderableBound);
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.transform = text.groupTransform;
gpuTextData.batchableSprite.bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 };
gpuTextData.batchableSprite.roundPixels = this._renderer._roundPixels | text._roundPixels;
this._gpuText[text.uid] = gpuTextData;
text._resolution = text._autoResolution ? this._renderer.resolution : text.resolution;
this._updateText(text);
text.on("destroyed", this._destroyRenderableBound);
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 canvas = canvasAndContext.canvas;
const { width, height } = canvas;
const key = (width << 17) + (height << 1);
this._canvasPool[key].push(canvasAndContext);
}
clear() {
this._canvasPool = {};
}
}
const CanvasPool = new CanvasPoolClass();
"use strict";
var __defProp$T = Object.defineProperty;
var __defProps$m = Object.defineProperties;
var __getOwnPropDescs$m = 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$m = (a, b) => __defProps$m(a, __getOwnPropDescs$m(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$m(__spreadValues$T({}, 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) {
/** unique id for this fill gradient */
this.uid = uid$1("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).toHexa() });
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) {
/** unique id for this fill pattern */
this.uid = uid$1("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
* @param out
* @returns The framing rectangle
*/
getBounds(out) {
out = out || new Rectangle();
out.x = this.x - this.halfWidth;
out.y = this.y - this.halfHeight;
out.width = this.halfWidth * 2;
out.height = this.halfHeight * 2;
return out;
}
/**
* 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 && !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 = [];
/** unique id for this graphics path */
this.uid = uid$1("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$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;
};
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$S(__spreadValues$S({}, fillStyle), f1);
} else if (f1) {
fillStyle = f1;
}
if (s1 && strokeStyle) {
strokeStyle = __spreadValues$S(__spreadValues$S({}, 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$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;
};
var __objRest$i = (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;
};
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$R(__spreadValues$R({}, defaultStyle), fill);
}
function handleFillPattern(fill, value, defaultStyle) {
fill.fill = value;
fill.color = 16777215;
fill.texture = value.texture;
fill.matrix = value.transform;
return __spreadValues$R(__spreadValues$R({}, 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$R(__spreadValues$R({}, defaultStyle), fill);
}
function handleFillObject(value, defaultStyle) {
var _a;
const style = __spreadValues$R(__spreadValues$R({}, defaultStyle), value);
if (style.texture) {
if (style.texture !== Texture.WHITE) {
const m = ((_a = style.matrix) == null ? void 0 : _a.invert()) || new Matrix();
m.translate(style.texture.frame.x, style.texture.frame.y);
m.scale(1 / style.texture.source.width, 1 / style.texture.source.height);
style.matrix = m;
}
const sourceStyle = style.texture.source.style;
if (sourceStyle.addressMode === "clamp-to-edge") {
sourceStyle.addressMode = "repeat";
sourceStyle.update();
}
}
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$i(_a, ["width", "alignment", "miterLimit", "cap", "join"]);
const fill = toFillStyle(value, rest);
if (!fill) {
return null;
}
return __spreadValues$R({
width,
alignment,
miterLimit,
cap,
join
}, fill);
}
"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;
};
const tmpPoint = new Point();
const tempMatrix$3 = new Matrix();
const _GraphicsContext = class _GraphicsContext extends EventEmitter {
constructor() {
super(...arguments);
/** unique id for this graphics context */
this.uid = uid$1("graphicsContext");
this.dirty = true;
this.batchMode = "auto";
this.instructions = [];
this._activePath = new GraphicsPath();
this._transform = new Matrix();
this._fillStyle = __spreadValues$Q({}, _GraphicsContext.defaultFillStyle);
this._strokeStyle = __spreadValues$Q({}, _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$Q({}, this._fillStyle);
clone._strokeStyle = __spreadValues$Q({}, 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$Q({}, this._fillStyle),
strokeStyle: __spreadValues$Q({}, 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$3.set(a, b, c, d, dx, dy);
this._transform.append(tempMatrix$3);
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",
"fontVariant",
"fontWeight",
"leading",
"letterSpacing",
"lineHeight",
"padding",
"textBaseline",
"trim",
"whiteSpace",
"wordWrap",
"wordWrapWidth",
"fontFamily",
"fontStyle",
"fontSize"
];
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$P = Object.defineProperty;
var __defProps$l = Object.defineProperties;
var __getOwnPropDescs$l = 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$l = (a, b) => __defProps$l(a, __getOwnPropDescs$l(b));
const _TextStyle = class _TextStyle extends EventEmitter {
constructor(style = {}) {
super();
convertV7Tov8Style(style);
const fullStyle = __spreadValues$P(__spreadValues$P({}, _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$P(__spreadValues$P({}, _TextStyle.defaultDropShadow), value));
} else {
this._dropShadow = value ? this._createProxy(__spreadValues$P({}, _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$P(__spreadValues$P({}, GraphicsContext.defaultFillStyle), value), () => {
this._fill = toFillStyle(
__spreadValues$P({}, 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$P(__spreadValues$P({}, GraphicsContext.defaultStrokeStyle), value), () => {
this._stroke = toStrokeStyle(
__spreadValues$P({}, 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$P({}, 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$l(__spreadValues$P({}, 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;
let height = Math.max(lineHeight, fontProperties.fontSize + strokeWidth) + (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;
}
/**
* Convenience 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) {
var _a;
if (fillStyle.texture === Texture.WHITE && !fillStyle.fill) {
return Color.shared.setValue(fillStyle.color).setAlpha((_a = fillStyle.alpha) != null ? _a : 1).toHexa();
} 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) {
text._resolution = text._autoResolution ? this._renderer.resolution : text.resolution;
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$O = Object.defineProperty;
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 __objRest$h = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$O.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$O)
for (var prop of __getOwnPropSymbols$O(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$O.call(source, prop))
target[prop] = source[prop];
}
return target;
};
class Graphics extends ViewContainer {
/**
* @param options - Options for the Graphics.
*/
constructor(options) {
if (options instanceof GraphicsContext) {
options = { context: options };
}
const _a = options || {}, { context, roundPixels } = _a, rest = __objRest$h(_a, ["context", "roundPixels"]);
super(__spreadValues$O({
label: "Graphics"
}, rest));
this.renderPipeId = "graphics";
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);
}
onViewUpdate() {
this._didViewChangeTick++;
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";
const localUniformMSDFBit = {
name: "local-uniform-msdf-bit",
vertex: {
header: (
/* wgsl */
`
struct LocalUniforms {
uColor:vec4<f32>,
uTransformMatrix:mat3x3<f32>,
uDistance: f32,
uRound:f32,
}
@group(2) @binding(0) var<uniform> 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<f32>,
uTransformMatrix:mat3x3<f32>,
uDistance: f32
}
@group(2) @binding(0) var<uniform> localUniforms : LocalUniforms;
`
),
main: (
/* wgsl */
`
outColor = vec4<f32>(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<f32>, shapeColor:vec4<f32>, 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<f32>(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<f32>" },
uTransformMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
uDistance: { value: 4, type: "f32" },
uRound: { value: 0, type: "f32" }
});
const maxTextures = getMaxTexturesPerBatch();
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 = [];
/** should the fill for this font be applied as a tint to the text. */
this.applyFillAsTint = true;
/** 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";
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;
};
const _DynamicBitmapFont = 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 = 0;
this._measureCache = /* @__PURE__ */ Object.create(null);
this._currentChars = [];
this._currentX = 0;
this._currentY = 0;
this._currentPageIndex = -1;
this._skipKerning = false;
const dynamicOptions = __spreadValues$N(__spreadValues$N({}, _DynamicBitmapFont.defaultOptions), options);
this._textureSize = dynamicOptions.textureSize;
this._mipmap = dynamicOptions.mipmap;
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;
}
this.applyFillAsTint = dynamicOptions.overrideFill;
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 > this._textureSize) {
currentY += maxCharHeight;
maxCharHeight = paddedHeight;
currentX = 0;
if (currentY + maxCharHeight > this._textureSize) {
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(
this._textureSize,
this._textureSize,
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",
autoGenerateMipmaps: this._mipmap
})
});
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];
canvasAndContext.canvas.width = canvasAndContext.canvas.width;
CanvasPool.returnCanvasAndContext(canvasAndContext);
texture.destroy(true);
}
this.pages = null;
}
};
_DynamicBitmapFont.defaultOptions = {
textureSize: 512,
style: new TextStyle(),
mipmap: true
};
let DynamicBitmapFont = _DynamicBitmapFont;
"use strict";
function getBitmapTextLayout(chars, style, font, trimEnd) {
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;
if (trimEnd) {
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$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;
};
let fontCount = 0;
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 && !style._stroke) {
fontFamilyKey += style._fill.fill.styleKey;
overrideFill = false;
} else if (style._stroke || style.dropShadow) {
let key = style.styleKey;
key = key.substring(0, key.lastIndexOf("-"));
fontFamilyKey = `${key}-bitmap`;
overrideFill = false;
}
if (!Cache.has(fontFamilyKey)) {
const fnt = new DynamicBitmapFont(__spreadValues$M({
style,
overrideFill,
overrideSize: true
}, this.defaultOptions));
fontCount++;
if (fontCount > 50) {
warn("BitmapText", `You have dynamically created ${fontCount} bitmap fonts, this can be inefficient. Try pre installing your font styles using \`BitmapFont.install({name:"style1", style})\``);
}
fnt.once("destroy", () => {
fontCount--;
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
* @param trimEnd - Whether to ignore whitespaces at the end of each line
*/
getLayout(text, style, trimEnd = true) {
const bitmapFont = this.getFont(text, style);
return getBitmapTextLayout([...text], style, bitmapFont, trimEnd);
}
/**
* Measure the text using the specified style.
* @param text - The text to measure
* @param style - The style to use
* @param trimEnd - Whether to ignore whitespaces at the end of each line
*/
measureText(text, style, trimEnd = true) {
return this.getLayout(text, style, trimEnd);
}
// 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$M(__spreadValues$M({}, 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 {
constructor(renderer) {
this._gpuBitmapText = {};
this._destroyRenderableBound = this.destroyRenderable.bind(this);
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) {
bitmapText.off("destroyed", this._destroyRenderableBound);
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) {
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 = bitmapFont.baseLineOffset;
const bitmapTextLayout = getBitmapTextLayout(chars, style, bitmapFont, true);
let index = 0;
const padding = style.padding;
const scale = bitmapTextLayout.scale;
let tx = bitmapTextLayout.width;
let ty = bitmapTextLayout.height + bitmapTextLayout.offsetY;
if (style._stroke) {
tx += style._stroke.width / scale;
ty += style._stroke.width / scale;
}
context.translate(-bitmapText._anchor._x * tx - padding, -bitmapText._anchor._y * ty - padding).scale(scale, scale);
const tint = bitmapFont.applyFillAsTint ? style._fill.color : 16777215;
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._destroyRenderableBound);
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._destroyRenderableBound = this.destroyRenderable.bind(this);
this._renderer = renderer;
this._renderer.runners.resolutionChange.add(this);
}
resolutionChange() {
for (const i in this._gpuText) {
const gpuText = this._gpuText[i];
if (!gpuText)
continue;
const text = gpuText.batchableSprite.renderable;
if (text._autoResolution) {
text._resolution = this._renderer.resolution;
text.onViewUpdate();
}
}
}
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, instructionSet) {
const gpuText = this._getGpuText(htmlText);
const batchableSprite = gpuText.batchableSprite;
if (htmlText._didTextUpdate) {
this._updateText(htmlText);
}
this._renderer.renderPipes.batch.addToBatch(batchableSprite, instructionSet);
}
updateRenderable(htmlText) {
const gpuText = this._getGpuText(htmlText);
const batchableSprite = gpuText.batchableSprite;
if (htmlText._didTextUpdate) {
this._updateText(htmlText);
}
batchableSprite._batcher.updateElement(batchableSprite);
}
destroyRenderable(htmlText) {
htmlText.off("destroyed", this._destroyRenderableBound);
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.transform = htmlText.groupTransform;
batchableSprite.texture = Texture.EMPTY;
batchableSprite.bounds = { minX: 0, maxX: 1, minY: 0, maxY: 0 };
batchableSprite.roundPixels = this._renderer._roundPixels | htmlText._roundPixels;
htmlText._resolution = htmlText._autoResolution ? this._renderer.resolution : htmlText.resolution;
this._gpuText[htmlText.uid] = gpuTextData;
htmlText.on("destroyed", this._destroyRenderableBound);
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$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;
};
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$L({}, 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({
fontWeight: style.fontWeight,
fontStyle: style.fontStyle,
fontFamily
}, 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 = `<style>${style.cssStyle}</style><div style='padding:0;'>${text}</div>`;
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 = `<style>${style.cssStyle};</style><div style='padding:0'>${text}</div>`;
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;
const doublePadding = style.padding * 2;
return {
width: contentBounds.width - doublePadding,
height: contentBounds.height + descenderPadding - doublePadding
};
}
"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;
const uvSafeOffset = 2;
image.width = (width | 0) + uvSafeOffset;
image.height = (height | 0) + uvSafeOffset;
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 - uvSafeOffset,
image.height - uvSafeOffset,
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$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;
};
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$K(__spreadValues$K({}, _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$J = Object.defineProperty;
var __defProps$k = Object.defineProperties;
var __getOwnPropDescs$k = 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$k = (a, b) => __defProps$k(a, __getOwnPropDescs$k(b));
const localUniformBit = {
name: "local-uniform-bit",
vertex: {
header: (
/* wgsl */
`
struct LocalUniforms {
uTransformMatrix:mat3x3<f32>,
uColor:vec4<f32>,
uRound:f32,
}
@group(1) @binding(0) var<uniform> 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$k(__spreadValues$J({}, localUniformBit), {
vertex: __spreadProps$k(__spreadValues$J({}, 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<f32>,
uClampFrame:vec4<f32>,
uClampOffset:vec2<f32>,
uTextureTransform:mat3x3<f32>,
uSizeAnchor:vec4<f32>
};
@group(2) @binding(0) var<uniform> tilingUniforms: TilingUniforms;
@group(2) @binding(1) var uTexture: texture_2d<f32>;
@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<f32>,
uClampFrame:vec4<f32>,
uClampOffset:vec2<f32>,
uTextureTransform:mat3x3<f32>,
uSizeAnchor:vec4<f32>
};
@group(2) @binding(0) var<uniform> tilingUniforms: TilingUniforms;
@group(2) @binding(1) var uTexture: texture_2d<f32>;
@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<f32>" },
uClampFrame: { value: new Float32Array([0, 0, 1, 1]), type: "vec4<f32>" },
uClampOffset: { value: new Float32Array([0, 0]), type: "vec2<f32>" },
uTextureTransform: { value: new Matrix(), type: "mat3x3<f32>" },
uSizeAnchor: { value: new Float32Array([100, 100, 0.5, 0.5]), type: "vec4<f32>" }
});
super({
glProgram,
gpuProgram,
resources: {
localUniforms: new UniformGroup({
uTransformMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
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._state = State.default2d;
this._tilingSpriteDataHash = /* @__PURE__ */ Object.create(null);
this._destroyRenderableBound = this.destroyRenderable.bind(this);
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 && 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.renderable = tilingSprite;
batchableMesh.transform = tilingSprite.groupTransform;
batchableMesh.texture = tilingSprite._texture;
}
batchableMesh.roundPixels = this._renderer._roundPixels | tilingSprite._roundPixels;
batcher.addToBatch(batchableMesh, instructionSet);
} 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._state.blendMode = getAdjustedBlendModeBlend(tilingSprite.groupBlendMode, tilingSprite.texture._source);
this._renderer.encoder.draw({
geometry: sharedQuad,
shader,
state: this._state
});
}
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;
tilingSprite.off("destroyed", this._destroyRenderableBound);
}
_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._destroyRenderableBound);
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$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 _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$I(__spreadValues$I({}, _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$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 _NineSliceGeometry = class _NineSliceGeometry extends PlaneGeometry {
constructor(options = {}) {
options = __spreadValues$H(__spreadValues$H({}, _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._destroyRenderableBound = this.destroyRenderable.bind(this);
this._renderer = renderer;
}
addRenderable(sprite, instructionSet) {
const gpuSprite = this._getGpuSprite(sprite);
if (sprite._didSpriteUpdate)
this._updateBatchableSprite(sprite, gpuSprite);
this._renderer.renderPipes.batch.addToBatch(gpuSprite, instructionSet);
}
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 batchableMesh = this._gpuSpriteHash[sprite.uid];
BigPool.return(batchableMesh.geometry);
BigPool.return(batchableMesh);
this._gpuSpriteHash[sprite.uid] = null;
sprite.off("destroyed", this._destroyRenderableBound);
}
_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 = BigPool.get(BatchableMesh);
batchableMesh.geometry = BigPool.get(NineSliceGeometry);
batchableMesh.renderable = sprite;
batchableMesh.transform = sprite.groupTransform;
batchableMesh.texture = sprite._texture;
batchableMesh.roundPixels = this._renderer._roundPixels | sprite._roundPixels;
sprite._didSpriteUpdate = true;
this._gpuSpriteHash[sprite.uid] = batchableMesh;
sprite.on("destroyed", this._destroyRenderableBound);
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$2 = 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$2).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]),
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<f32>" },
uInputPixel: { value: new Float32Array(4), type: "vec4<f32>" },
uInputClamp: { value: new Float32Array(4), type: "vec4<f32>" },
uOutputFrame: { value: new Float32Array(4), type: "vec4<f32>" },
uGlobalFrame: { value: new Float32Array(4), type: "vec4<f32>" },
uOutputTexture: { value: new Float32Array(4), type: "vec4<f32>" }
});
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.renderTarget.colorTexture.source;
let resolution = Infinity;
let padding = 0;
let antialias = true;
let blendRequired = false;
let enabled = false;
for (let i = 0; i < filters.length; i++) {
const filter = filters[i];
resolution = Math.min(resolution, filter.resolution === "inherit" ? colorTextureSource._resolution : filter.resolution);
padding += filter.padding;
if (filter.antialias === "off") {
antialias = false;
} else if (filter.antialias === "inherit") {
antialias && (antialias = colorTextureSource.antialias);
}
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).ceil().scale(1 / resolution).pad(padding | 0);
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$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 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$G(__spreadValues$G({}, defaultSystemOptions), options);
}
options = __spreadValues$G(__spreadValues$G({}, _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) {
const previousResolution = this.view.resolution;
this.view.resize(desiredScreenWidth, desiredScreenHeight, resolution);
this.emit("resize", this.view.screen.width, this.view.screen.height, this.view.resolution);
if (resolution !== void 0 && resolution !== previousResolution) {
this.runners.resolutionChange.emit(resolution);
}
}
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;
}
/**
* Overridable 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 gpu.requestAdapter(options);
await adapter.requestDevice();
return true;
} catch (e) {
return false;
}
})();
return _isWebGPUSupported;
}
"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 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$F(__spreadValues$F({}, 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$F(__spreadValues$F({}, options), options.webgl);
break;
} else if (rendererType === "canvas") {
finalOptions = __spreadValues$F({}, 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";
const DATA_URI = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;charset=([\w-]+))?(?:;(base64))?,(.*)/i;
const VERSION = "8.4.1";
"use strict";
class ApplicationInitHook {
static init() {
var _a;
(_a = globalThis.__PIXI_APP_INIT__) == null ? void 0 : _a.call(globalThis, this, VERSION);
}
static destroy() {
}
}
/** @ignore */
ApplicationInitHook.extension = ExtensionType.Application;
class RendererInitHook {
constructor(renderer) {
this._renderer = renderer;
}
init() {
var _a;
(_a = globalThis.__PIXI_RENDERER_INIT__) == null ? void 0 : _a.call(globalThis, this._renderer, VERSION);
}
destroy() {
this._renderer = null;
}
}
/** @ignore */
RendererInitHook.extension = {
type: [
ExtensionType.WebGLSystem,
ExtensionType.WebGPUSystem
],
name: "initHook",
priority: -10
};
"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 _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$E({}, 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);
extensions.add(ApplicationInitHook);
"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("<font>")) {
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$D = Object.defineProperty;
var __defProps$j = Object.defineProperties;
var __getOwnPropDescs$j = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$j = (a, b) => __defProps$j(a, __getOwnPropDescs$j(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,
data: {}
}));
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$j(__spreadValues$D({}, 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$C = Object.defineProperty;
var __defProps$i = Object.defineProperties;
var __getOwnPropDescs$i = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$i = (a, b) => __defProps$i(a, __getOwnPropDescs$i(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$i(__spreadValues$C({}, 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$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;
};
var __objRest$g = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$B.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$B)
for (var prop of __getOwnPropSymbols$B(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$B.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$g(_f, ["parseAsGraphicsContext"]);
const base = new ImageSource(__spreadValues$B({
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, alphaMode) {\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 return alphaMode === \"premultiplied-alpha\" ? createImageBitmap(imageBlob, { premultiplyAlpha: \"none\" }) : createImageBitmap(imageBlob);\n }\n self.onmessage = async (event) => {\n try {\n const imageBitmap = await loadImageBitmap(event.data.data[0], event.data.data[1]);\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, asset) {
var _a;
return this._run("loadImageBitmap", [src, (_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.alphaMode]);
}
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$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 validImageExtensions = [".jpeg", ".jpg", ".png", ".webp", ".avif"];
const validImageMIMEs = [
"image/jpeg",
"image/png",
"image/webp",
"image/avif"
];
async function loadImageBitmap(url, asset) {
var _a;
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();
return ((_a = asset == null ? void 0 : asset.data) == null ? void 0 : _a.alphaMode) === "premultiplied-alpha" ? createImageBitmap(imageBlob, { premultiplyAlpha: "none" }) : createImageBitmap(imageBlob);
}
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, asset);
} else {
src = await loadImageBitmap(url, asset);
}
} 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$A({
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$z = Object.defineProperty;
var __defProps$h = Object.defineProperties;
var __getOwnPropDescs$h = 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$h = (a, b) => __defProps$h(a, __getOwnPropDescs$h(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$z(__spreadProps$h(__spreadValues$z({}, 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$h(__spreadValues$z({}, 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 initial 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 DOMAdapter.get().getNavigator().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;
} else {
container.culled = false;
}
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$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$f = (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 _Filter = class _Filter extends Shader {
/**
* @param options - The optional parameters of this filter.
*/
constructor(options) {
options = __spreadValues$y(__spreadValues$y({}, _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.blendMode = options.blendMode;
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$f(_a, ["gpu", "gl"]);
let gpuProgram;
let glProgram;
if (gpu) {
gpuProgram = GpuProgram.from(gpu);
}
if (gl) {
glProgram = GlProgram.from(gl);
}
return new _Filter(__spreadValues$y({
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 float blendedAlpha = front.a + back.a * (1.0 - front.a);\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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct BlendUniforms {\n uBlend:f32,\n};\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n@group(0) @binding(3) var uBackTexture: texture_2d<f32>;\n\n@group(1) @binding(0) var<uniform> blendUniforms : BlendUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\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<f32>, \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<f32>\n) -> @location(0) vec4<f32> {\n\n\n var back = textureSample(uBackTexture, uSampler, uv);\n var front = textureSample(uTexture, uSampler, uv);\n var blendedAlpha = front.a + back.a * (1.0 - front.a);\n \n var out = vec4<f32>(0.0,0.0,0.0,0.0);\n\n {MAIN}\n\n return out;\n}";
"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;
};
class BlendModeFilter extends Filter {
constructor(options) {
const gpuOptions = options.gpu;
const gpuSource = compileBlendModeShader(__spreadValues$x({ 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$x({ 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>) -> f32
{
return 0.3*c.r + 0.59*c.g + 0.11*c.b;
}
fn setLuminosity(c: vec3<f32>, lum: f32) -> vec3<f32>
{
var modLum: f32 = lum - getLuminosity(c);
var color: vec3<f32> = c.rgb + modLum;
// clip back into legal range
modLum = getLuminosity(color);
let modLumVec = vec3<f32>(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>) -> f32
{
return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b));
}
fn setSaturationMinMidMax(cSorted: vec3<f32>, s: f32) -> vec3<f32>
{
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<f32>, s: f32) -> vec3<f32>
{
var color = c;
if (color.r <= color.g && color.r <= color.b)
{
if (color.g <= color.b)
{
color = vec3<f32>(setSaturationMinMidMax(color.rgb, s)).rgb;
}
else
{
color = vec3<f32>(setSaturationMinMidMax(color.rbg, s)).rbg;
}
}
else if (color.g <= color.r && color.g <= color.b)
{
if (color.r <= color.b)
{
color = vec3<f32>(setSaturationMinMidMax(color.grb, s)).grb;
}
else
{
color = vec3<f32>(setSaturationMinMidMax(color.gbr, s)).gbr;
}
}
else
{
// Using bgr for both fixes part of hue
if (color.r <= color.g)
{
color = vec3<f32>(setSaturationMinMidMax(color.brg, s)).brg;
}
else
{
color = vec3<f32>(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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct AlphaUniforms {\n uAlpha:f32,\n};\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> alphaUniforms : AlphaUniforms;\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2<f32>\n{\n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition)\n );\n}\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2<f32>,\n @builtin(position) position: vec4<f32>\n) -> @location(0) vec4<f32> {\n \n var sample = textureSample(uTexture, uSampler, uv);\n \n return sample * alphaUniforms.uAlpha;\n}";
"use strict";
var __defProp$w = Object.defineProperty;
var __defProps$g = Object.defineProperties;
var __getOwnPropDescs$g = 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$g = (a, b) => __defProps$g(a, __getOwnPropDescs$g(b));
var __objRest$e = (source2, exclude) => {
var target = {};
for (var prop in source2)
if (__hasOwnProp$w.call(source2, prop) && exclude.indexOf(prop) < 0)
target[prop] = source2[prop];
if (source2 != null && __getOwnPropSymbols$w)
for (var prop of __getOwnPropSymbols$w(source2)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$w.call(source2, prop))
target[prop] = source2[prop];
}
return target;
};
const _AlphaFilter = class _AlphaFilter extends Filter {
constructor(options) {
options = __spreadValues$w(__spreadValues$w({}, _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$e(_a, ["alpha"]);
const alphaUniforms = new UniformGroup({
uAlpha: { value: alpha, type: "f32" }
});
super(__spreadProps$g(__spreadValues$w({}, 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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct BlurUniforms {\n uStrength:f32,\n};\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> blurUniforms : BlurUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n %blur-struct%\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2<f32>\n{\n return gfu.uGlobalFrame.zw;\n}\n\n\n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \n) -> VSOutput {\n\n let filteredCord = filterTextureCoord(aPosition);\n\n let pixelStrength = gfu.uInputSize.%dimension% * 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<f32>,\n %blur-fragment-in%\n) -> @location(0) vec4<f32> {\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<f32>,`;
if (horizontal) {
blurOutSource[i] = `filteredCord + vec2(${i - halfLength + 1} * pixelStrength, 0.0),`;
} else {
blurOutSource[i] = `filteredCord + vec2(0.0, ${i - halfLength + 1} * pixelStrength),`;
}
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).replace("%dimension%", horizontal ? "z" : "w");
return GpuProgram.from({
vertex: {
source: finalSource,
entryPoint: "mainVertex"
},
fragment: {
source: finalSource,
entryPoint: "mainFragment"
}
});
}
"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;
};
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$v(__spreadValues$v({}, _BlurFilterPass.defaultOptions), options);
const glProgram = generateBlurGlProgram(options.horizontal, options.kernelSize);
const gpuProgram = generateBlurProgram(options.horizontal, options.kernelSize);
super(__spreadValues$v({
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;
const shouldClear = filterManager.renderer.type === RendererType.WEBGPU;
for (let i = 0; i < this.passes - 1; i++) {
filterManager.applyFilter(this, flip, flop, i === 0 ? true : shouldClear);
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$u = Object.defineProperty;
var __defProps$f = Object.defineProperties;
var __getOwnPropDescs$f = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$f = (a, b) => __defProps$f(a, __getOwnPropDescs$f(b));
var __objRest$d = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$u.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$u)
for (var prop of __getOwnPropSymbols$u(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$u.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] !== void 0)
options.quality = args[1];
if (args[2] !== void 0)
options.resolution = args[2] || "inherit";
if (args[3] !== void 0)
options.kernelSize = args[3];
}
options = __spreadValues$u(__spreadValues$u({}, BlurFilterPass.defaultOptions), options);
const _b = options, { strength, strengthX, strengthY, quality } = _b, rest = __objRest$d(_b, ["strength", "strengthX", "strengthY", "quality"]);
super(__spreadProps$f(__spreadValues$u({}, rest), {
compatibleRenderers: RendererType.BOTH,
resources: {}
}));
this._repeatEdgePixels = false;
this.blurXFilter = new BlurFilterPass(__spreadValues$u({ horizontal: true }, options));
this.blurYFilter = new BlurFilterPass(__spreadValues$u({ horizontal: false }, options));
this.quality = quality;
this.strengthX = strengthX != null ? strengthX : strength;
this.strengthY = strengthY != null ? strengthY : 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.blendMode = "normal";
this.blurXFilter.apply(filterManager, input, tempTexture, true);
this.blurYFilter.blendMode = this.blendMode;
this.blurYFilter.apply(filterManager, tempTexture, output, clearMode);
TexturePool.returnTexture(tempTexture);
} else if (yStrength) {
this.blurYFilter.blendMode = this.blendMode;
this.blurYFilter.apply(filterManager, input, output, clearMode);
} else {
this.blurXFilter.blendMode = this.blendMode;
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 8
*/
get strength() {
if (this.strengthX !== this.strengthY) {
throw new Error("BlurFilter's strengthX and strengthY are different");
}
return this.strengthX;
}
set strength(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 horizontal blur
* @default 8
*/
get strengthX() {
return this.blurXFilter.blur;
}
set strengthX(value) {
this.blurXFilter.blur = value;
this.updatePadding();
}
/**
* Sets the strength of the vertical blur
* @default 8
*/
get strengthY() {
return this.blurYFilter.blur;
}
set strengthY(value) {
this.blurYFilter.blur = value;
this.updatePadding();
}
/**
* Sets the strength of both the blurX and blurY properties simultaneously
* @default 2
* @deprecated since 8.3.0
* @see BlurFilter.strength
*/
get blur() {
deprecation("8.3.0", "BlurFilter.blur is deprecated, please use BlurFilter.strength instead.");
return this.strength;
}
set blur(value) {
deprecation("8.3.0", "BlurFilter.blur is deprecated, please use BlurFilter.strength instead.");
this.strength = value;
}
/**
* Sets the strength of the blurX property
* @default 2
* @deprecated since 8.3.0
* @see BlurFilter.strengthX
*/
get blurX() {
deprecation("8.3.0", "BlurFilter.blurX is deprecated, please use BlurFilter.strengthX instead.");
return this.strengthX;
}
set blurX(value) {
deprecation("8.3.0", "BlurFilter.blurX is deprecated, please use BlurFilter.strengthX instead.");
this.strengthX = value;
}
/**
* Sets the strength of the blurY property
* @default 2
* @deprecated since 8.3.0
* @see BlurFilter.strengthY
*/
get blurY() {
deprecation("8.3.0", "BlurFilter.blurY is deprecated, please use BlurFilter.strengthY instead.");
return this.strengthY;
}
set blurY(value) {
deprecation("8.3.0", "BlurFilter.blurY is deprecated, please use BlurFilter.strengthY instead.");
this.strengthY = 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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct ColorMatrixUniforms {\n uColorMatrix:array<vec4<f32>, 5>,\n uAlpha:f32,\n};\n\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n@group(1) @binding(0) var<uniform> colorMatrixUniforms : ColorMatrixUniforms;\n\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>,\n };\n \nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition),\n );\n}\n\n\n@fragment\nfn mainFragment(\n @location(0) uv: vec2<f32>,\n) -> @location(0) vec4<f32> {\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<f32>(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$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));
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$e(__spreadValues$t({}, 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 brightness (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 independent 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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct DisplacementUniforms {\n uFilterMatrix:mat3x3<f32>,\n uScale:vec2<f32>,\n uRotation:mat2x2<f32>\n};\n\n\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> filterUniforms : DisplacementUniforms;\n@group(1) @binding(1) var uMapTexture: texture_2d<f32>;\n@group(1) @binding(2) var uMapSampler : sampler;\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>,\n @location(1) filterUv : vec2<f32>,\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getFilterCoord(aPosition:vec2<f32> ) -> vec2<f32>\n{\n return ( filterUniforms.uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;\n}\n\nfn getSize() -> vec2<f32>\n{\n\n \n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \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<f32>,\n @location(1) filterUv: vec2<f32>,\n @builtin(position) position: vec4<f32>\n) -> @location(0) vec4<f32> {\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$s = Object.defineProperty;
var __defProps$d = Object.defineProperties;
var __getOwnPropDescs$d = 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$d = (a, b) => __defProps$d(a, __getOwnPropDescs$d(b));
var __objRest$c = (source2, exclude) => {
var target = {};
for (var prop in source2)
if (__hasOwnProp$s.call(source2, prop) && exclude.indexOf(prop) < 0)
target[prop] = source2[prop];
if (source2 != null && __getOwnPropSymbols$s)
for (var prop of __getOwnPropSymbols$s(source2)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$s.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$c(_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<f32>" },
uScale: { value: scale, type: "vec2<f32>" },
uRotation: { value: new Float32Array([0, 0, 0, 0]), type: "mat2x2<f32>" }
});
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$d(__spreadValues$s({}, 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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>,\n};\n\nstruct NoiseUniforms {\n uNoise:f32,\n uSeed:f32,\n};\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> noiseUniforms : NoiseUniforms;\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getSize() -> vec2<f32>\n{\n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \n) -> VSOutput {\n return VSOutput(\n filterVertexPosition(aPosition),\n filterTextureCoord(aPosition)\n );\n}\n\nfn rand(co:vec2<f32>) -> 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<f32>,\n @builtin(position) position: vec4<f32>\n) -> @location(0) vec4<f32> {\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$r = Object.defineProperty;
var __defProps$c = Object.defineProperties;
var __getOwnPropDescs$c = 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$c = (a, b) => __defProps$c(a, __getOwnPropDescs$c(b));
var __objRest$b = (source2, exclude) => {
var target = {};
for (var prop in source2)
if (__hasOwnProp$r.call(source2, prop) && exclude.indexOf(prop) < 0)
target[prop] = source2[prop];
if (source2 != null && __getOwnPropSymbols$r)
for (var prop of __getOwnPropSymbols$r(source2)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$r.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$r(__spreadValues$r({}, _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$b(_a, ["noise", "seed"]);
super(__spreadProps$c(__spreadValues$r({}, 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<f32>,\n uInputPixel:vec4<f32>,\n uInputClamp:vec4<f32>,\n uOutputFrame:vec4<f32>,\n uGlobalFrame:vec4<f32>,\n uOutputTexture:vec4<f32>, \n};\n\nstruct MaskUniforms {\n uFilterMatrix:mat3x3<f32>,\n uMaskClamp:vec4<f32>,\n uAlpha:f32,\n};\n\n\n@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;\n@group(0) @binding(1) var uTexture: texture_2d<f32>;\n@group(0) @binding(2) var uSampler : sampler;\n\n@group(1) @binding(0) var<uniform> filterUniforms : MaskUniforms;\n@group(1) @binding(1) var uMaskTexture: texture_2d<f32>;\n\nstruct VSOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) uv : vec2<f32>,\n @location(1) filterUv : vec2<f32>,\n };\n\nfn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>\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<f32> ) -> vec2<f32>\n{\n return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);\n}\n\nfn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>\n{\n return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw); \n}\n\nfn getFilterCoord(aPosition:vec2<f32> ) -> vec2<f32>\n{\n return ( filterUniforms.uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;\n}\n\nfn getSize() -> vec2<f32>\n{\n\n \n return gfu.uGlobalFrame.zw;\n}\n \n@vertex\nfn mainVertex(\n @location(0) aPosition : vec2<f32>, \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<f32>,\n @location(1) filterUv: vec2<f32>,\n @builtin(position) position: vec4<f32>\n) -> @location(0) vec4<f32> {\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$q = Object.defineProperty;
var __defProps$b = Object.defineProperties;
var __getOwnPropDescs$b = 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$b = (a, b) => __defProps$b(a, __getOwnPropDescs$b(b));
var __objRest$a = (source2, exclude) => {
var target = {};
for (var prop in source2)
if (__hasOwnProp$q.call(source2, prop) && exclude.indexOf(prop) < 0)
target[prop] = source2[prop];
if (source2 != null && __getOwnPropSymbols$q)
for (var prop of __getOwnPropSymbols$q(source2)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$q.call(source2, prop))
target[prop] = source2[prop];
}
return target;
};
class MaskFilter extends Filter {
constructor(options) {
const _a = options, { sprite } = _a, rest = __objRest$a(_a, ["sprite"]);
const textureMatrix = new TextureMatrix(sprite.texture);
const filterUniforms = new UniformGroup({
uFilterMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
uMaskClamp: { value: textureMatrix.uClampFrame, type: "vec4<f32>" },
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$b(__spreadValues$q({}, 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>) -> f32 {\n return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;\n}\n\nfn setLuminosity(c: vec3<f32>, lum: f32) -> vec3<f32> {\n let d: f32 = lum - getLuminosity(c);\n let newColor: vec3<f32> = c.rgb + vec3<f32>(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<f32>(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>) -> 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<f32>, s: f32) -> vec3<f32> {\n var result: vec3<f32>;\n if (cSorted.z > cSorted.x) {\n let newY = (((cSorted.y - cSorted.x) * s) / (cSorted.z - cSorted.x));\n result = vec3<f32>(0.0, newY, s);\n } else {\n result = vec3<f32>(0.0, 0.0, 0.0);\n }\n return vec3<f32>(result.x, result.y, result.z);\n}\n\nfn setSaturation(c: vec3<f32>, s: f32) -> vec3<f32> {\n var result: vec3<f32> = 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<f32> = vec3<f32>(result.r, result.b, result.g);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3<f32>(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<f32> = vec3<f32>(result.g, result.r, result.b);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3<f32>(temp.g, temp.r, temp.b);\n } else {\n var temp: vec3<f32> = vec3<f32>(result.g, result.b, result.r);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3<f32>(temp.g, temp.b, temp.r);\n }\n } else {\n if (c.r <= c.g) {\n var temp: vec3<f32> = vec3<f32>(result.b, result.r, result.g);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3<f32>(temp.b, temp.r, temp.g);\n } else {\n var temp: vec3<f32> = vec3<f32>(result.b, result.g, result.r);\n temp = setSaturationMinMidMax(temp, s);\n result = vec3<f32>(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 {rendering.Renderer} renderer - A reference to the current 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$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;
};
var __objRest$9 = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$p.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$p)
for (var prop of __getOwnPropSymbols$p(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$p.call(source, prop))
target[prop] = source[prop];
}
return target;
};
class Mesh extends ViewContainer {
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$9(_a, ["geometry", "shader", "texture", "roundPixels", "state"]);
super(__spreadValues$p({
label: "Mesh"
}, rest));
this.renderPipeId = "mesh";
/** @ignore */
this._shader = null;
this.allowChildren = false;
this.shader = shader != null ? shader : null;
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;
}
/** 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.state.data & 12) !== 0)
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._didViewChangeTick++;
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";
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$8 = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$o.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$o)
for (var prop of __getOwnPropSymbols$o(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$o.call(source, prop))
target[prop] = source[prop];
}
return target;
};
class AnimatedSprite extends Sprite {
/** @ignore */
constructor(...args) {
let options = args[0];
if (Array.isArray(args[0])) {
options = {
textures: args[0],
autoUpdate: args[1]
};
}
const _a = options, { textures, autoUpdate } = _a, rest = __objRest$8(_a, ["textures", "autoUpdate"]);
const [firstFrame] = textures;
super(__spreadProps$a(__spreadValues$o({}, rest), {
texture: firstFrame instanceof Texture ? firstFrame : firstFrame.texture
}));
this._textures = null;
this._durations = null;
this._autoUpdate = autoUpdate != null ? autoUpdate : true;
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$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$7 = (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;
};
const _TilingSprite = class _TilingSprite extends ViewContainer {
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$n(__spreadValues$n({}, _TilingSprite.defaultOptions), options);
const _a = options != null ? options : {}, {
texture,
anchor,
tilePosition,
tileScale,
tileRotation,
width,
height,
applyAnchorToTexture,
roundPixels
} = _a, rest = __objRest$7(_a, [
"texture",
"anchor",
"tilePosition",
"tileScale",
"tileRotation",
"width",
"height",
"applyAnchorToTexture",
"roundPixels"
]);
super(__spreadValues$n({
label: "TilingSprite"
}, rest));
this.renderPipeId = "tilingSprite";
this.batched = 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$n({
texture: Cache.get(source)
}, options));
}
return new _TilingSprite(__spreadValues$n({
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;
}
/**
* 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;
}
/**
* Sets the size of the TilingSprite 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;
if (typeof value === "object") {
height = (_a = value.height) != null ? _a : value.width;
value = value.width;
}
this._width = value;
this._height = height != null ? height : value;
this.onViewUpdate();
}
/**
* Retrieves the size of the TilingSprite 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 TilingSprite.
*/
getSize(out) {
out || (out = {});
out.width = this._width;
out.height = this._height;
return out;
}
_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._didViewChangeTick++;
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$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$6 = (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 AbstractText extends ViewContainer {
constructor(options, styleClass) {
const _a = options, { text, resolution, style, anchor, width, height, roundPixels } = _a, rest = __objRest$6(_a, ["text", "resolution", "style", "anchor", "width", "height", "roundPixels"]);
super(__spreadValues$m({}, rest));
this.batched = true;
this._resolution = null;
this._autoResolution = true;
this._didTextUpdate = 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 !== void 0)
this.width = width;
if (height !== void 0)
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);
}
/** 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._autoResolution = value === null;
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.TextStyle> |
* text.TextStyleOptions |
* text.HTMLTextStyle |
* Partial<text.HTMLTextStyle> |
* 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) {
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;
if (typeof value === "object") {
height = (_a = value.height) != null ? _a : value.width;
value = value.width;
} else {
height != null ? height : height = value;
}
value !== void 0 && this._setWidth(value, this.bounds.width);
height !== void 0 && this._setHeight(height, 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._didViewChangeTick++;
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 anchor = this._anchor;
const canvasMeasurement = CanvasTextMetrics.measureText(
this._text,
this._style
);
const { width, height } = canvasMeasurement;
bounds.minX = -anchor._x * width;
bounds.maxX = bounds.minX + width;
bounds.minY = -anchor._y * height;
bounds.maxY = bounds.minY + height;
}
}
"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 anchor = this._anchor;
const bitmapMeasurement = BitmapFontManager.measureText(this.text, this._style);
const scale = bitmapMeasurement.scale;
const offset = bitmapMeasurement.offsetY * scale;
let width = bitmapMeasurement.width * scale;
let height = bitmapMeasurement.height * scale;
const stroke = this._style._stroke;
if (stroke) {
width += stroke.width;
height += stroke.width;
}
bounds.minX = -anchor._x * width;
bounds.maxX = bounds.minX + width;
bounds.minY = -anchor._y * (height + offset);
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 anchor = this._anchor;
const htmlMeasurement = measureHtmlText(this.text, this._style);
const { width, height } = htmlMeasurement;
bounds.minX = -anchor._x * width;
bounds.maxX = bounds.minX + width;
bounds.minY = -anchor._y * height;
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) {
batcherPipe.renderer.runners.contextChange.add(this);
}
contextChange() {
this._didUpload = false;
}
start(batchPipe, geometry, shader) {
const renderer = batchPipe.renderer;
renderer.shader.bind(shader, this._didUpload);
renderer.shader.updateUniformGroup(renderer.globalUniforms.uniformGroup);
renderer.geometry.bind(geometry, 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 < batch.textures.count; i++) {
renderer.texture.bind(textures[i], i);
}
renderer.geometry.draw("triangle-list", batch.size, batch.start);
}
}
/** @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 {
start(batchPipe, geometry, shader) {
const renderer = batchPipe.renderer;
const encoder = renderer.encoder;
const program = shader.gpuProgram;
this._shader = shader;
this._geometry = geometry;
encoder.setGeometry(geometry, program);
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);
}
}
/** @ignore */
GpuBatchAdaptor.extension = {
type: [
ExtensionType.WebGPUPipesAdaptor
],
name: "batch"
};
"use strict";
const _BatcherPipe = class _BatcherPipe {
constructor(renderer, adaptor) {
this.state = State.for2d();
this._batchersByInstructionSet = /* @__PURE__ */ Object.create(null);
/** A record of all active batchers, keyed by their names */
this._activeBatches = /* @__PURE__ */ Object.create(null);
var _a, _b;
this.renderer = renderer;
this._adaptor = adaptor;
(_b = (_a = this._adaptor).init) == null ? void 0 : _b.call(_a, this);
}
static getBatcher(name) {
return new this._availableBatchers[name]();
}
buildStart(instructionSet) {
let batchers = this._batchersByInstructionSet[instructionSet.uid];
if (!batchers) {
batchers = this._batchersByInstructionSet[instructionSet.uid] = /* @__PURE__ */ Object.create(null);
batchers.default || (batchers.default = new DefaultBatcher());
}
this._activeBatches = batchers;
this._activeBatch = this._activeBatches.default;
for (const i in this._activeBatches) {
this._activeBatches[i].begin();
}
}
addToBatch(batchableObject, instructionSet) {
if (this._activeBatch.name !== batchableObject.batcherName) {
this._activeBatch.break(instructionSet);
let batch = this._activeBatches[batchableObject.batcherName];
if (!batch) {
batch = this._activeBatches[batchableObject.batcherName] = _BatcherPipe.getBatcher(batchableObject.batcherName);
batch.begin();
}
this._activeBatch = batch;
}
this._activeBatch.add(batchableObject);
}
break(instructionSet) {
this._activeBatch.break(instructionSet);
}
buildEnd(instructionSet) {
this._activeBatch.break(instructionSet);
const batches = this._activeBatches;
for (const i in batches) {
const batch = batches[i];
const geometry = batch.geometry;
geometry.indexBuffer.setDataWithSize(batch.indexBuffer, batch.indexSize, true);
geometry.buffers[0].setDataWithSize(batch.attributeBuffer.float32View, batch.attributeSize, false);
}
}
upload(instructionSet) {
const batchers = this._batchersByInstructionSet[instructionSet.uid];
for (const i in batchers) {
const batcher = batchers[i];
const geometry = batcher.geometry;
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 = batcher.geometry;
const shader = batcher.shader;
this._adaptor.start(this, geometry, shader);
}
this._adaptor.execute(this, batch);
}
destroy() {
this.state = null;
this.renderer = null;
this._adaptor = null;
for (const i in this._activeBatches) {
this._activeBatches[i].destroy();
}
this._activeBatches = null;
}
};
/** @ignore */
_BatcherPipe.extension = {
type: [
ExtensionType.WebGLPipes,
ExtensionType.WebGPUPipes,
ExtensionType.CanvasPipes
],
name: "batch"
};
_BatcherPipe._availableBatchers = /* @__PURE__ */ Object.create(null);
let BatcherPipe = _BatcherPipe;
extensions.handleByMap(ExtensionType.Batcher, BatcherPipe._availableBatchers);
extensions.add(DefaultBatcher);
"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<f32>,
}
@group(2) @binding(2) var<uniform> textureUniforms : TextureUniforms;
`
),
main: (
/* wgsl */
`
uv = (textureUniforms.uTextureMatrix * vec3(uv, 1.0)).xy;
`
)
},
fragment: {
header: (
/* wgsl */
`
@group(2) @binding(0) var uTexture: texture_2d<f32>;
@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, rendererOrPipes) {
const root = renderGroup.root;
const instructionSet = renderGroup.instructionSet;
instructionSet.reset();
const renderer = rendererOrPipes.renderPipes ? rendererOrPipes : rendererOrPipes.batch.renderer;
const renderPipes = renderer.renderPipes;
renderPipes.batch.buildStart(instructionSet);
renderPipes.blendMode.buildStart();
renderPipes.colorMask.buildStart();
if (root.sortableChildren) {
root.sortChildren();
}
collectAllRenderablesAdvanced(root, instructionSet, renderer, true);
renderPipes.batch.buildEnd(instructionSet);
renderPipes.blendMode.buildEnd(instructionSet);
}
function collectAllRenderables(container, instructionSet, rendererOrPipes) {
const renderer = rendererOrPipes.renderPipes ? rendererOrPipes : rendererOrPipes.batch.renderer;
if (container.globalDisplayStatus < 7 || !container.includeInBuild)
return;
if (container.sortableChildren) {
container.sortChildren();
}
if (container.isSimple) {
collectAllRenderablesSimple(container, instructionSet, renderer);
} else {
collectAllRenderablesAdvanced(container, instructionSet, renderer, false);
}
}
function collectAllRenderablesSimple(container, instructionSet, renderer) {
if (container.renderPipeId) {
const { renderPipes, renderableGC } = renderer;
renderPipes.blendMode.setBlendMode(container, container.groupBlendMode, instructionSet);
container.didViewUpdate = false;
const rp = renderPipes;
rp[container.renderPipeId].addRenderable(container, instructionSet);
renderableGC.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, renderer);
}
}
}
function collectAllRenderablesAdvanced(container, instructionSet, renderer, isRoot) {
const { renderPipes, renderableGC } = renderer;
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);
renderableGC.addRenderable(container, instructionSet);
}
const children = container.children;
if (children.length) {
for (let i = 0; i < children.length; i++) {
collectAllRenderables(children[i], instructionSet, renderer);
}
}
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),
resolution: "inherit",
antialias: "inherit"
})];
}
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
);
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 colorTextureSource = renderer.renderTarget.renderTarget.colorTexture.source;
const filterTexture = TexturePool.getOptimalTexture(
bounds.width,
bounds.height,
colorTextureSource._resolution,
colorTextureSource.antialias
);
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) {
if (renderer.type === RendererType.WEBGL) {
renderer.renderTarget.finishRenderPass();
}
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
);
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$l = Object.defineProperty;
var __defProps$9 = Object.defineProperties;
var __getOwnPropDescs$9 = Object.getOwnPropertyDescriptors;
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 __spreadProps$9 = (a, b) => __defProps$9(a, __getOwnPropDescs$9(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$l(__spreadValues$l({}, _GlContextSystem.defaultOptions), options);
let multiView = this.multiView = options.multiView;
if (options.context && multiView) {
warn("Renderer created with both a context and multiview enabled. Disabling multiView as both cannot work together.");
multiView = false;
}
if (multiView) {
this.canvas = DOMAdapter.get().createCanvas(this._renderer.canvas.width, this._renderer.canvas.height);
} else {
this.canvas = this._renderer.view.canvas;
}
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"
});
}
}
ensureCanvasSize(targetCanvas) {
if (!this.multiView) {
if (targetCanvas !== this.canvas) {
warn("multiView is disabled, but targetCanvas is not the main canvas");
}
return;
}
const { canvas } = this;
if (canvas.width < targetCanvas.width || canvas.height < targetCanvas.height) {
canvas.width = Math.max(targetCanvas.width, targetCanvas.width);
canvas.height = Math.max(targetCanvas.height, targetCanvas.height);
}
}
/**
* 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.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$9(__spreadValues$l({}, 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$9(__spreadValues$l({}, 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,
/**
* {@link WebGLOptions.multiView}
* @default false
*/
multiView: false
};
let GlContextSystem = _GlContextSystem;
"use strict";
"use strict";
"use strict";
function ensureAttributes(geometry, extractedData) {
var _a, _b, _c;
for (const i in geometry.attributes) {
const attribute = geometry.attributes[i];
const attributeData = extractedData[i];
if (attributeData) {
(_a = attribute.format) != null ? _a : attribute.format = attributeData.format;
(_b = attribute.offset) != null ? _b : attribute.offset = attributeData.offset;
(_c = attribute.instance) != null ? _c : 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, _b;
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 = programAttrib.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) {
const divisor = (_b = attribute.divisor) != null ? _b : 1;
gl.vertexAttribDivisor(location, divisor);
} 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$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;
};
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$k(__spreadValues$k({}, _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();
}
/**
* Overridable 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<f32>": 8,
"vec3<f32>": 12,
"vec4<f32>": 16,
"mat2x2<f32>": 16 * 2,
"mat3x3<f32>": 16 * 3,
"mat4x4<f32>": 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<f32>",
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<f32>",
test: (data) => data.type === "vec4<f32>" && 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<f32>",
test: (data) => data.type === "vec2<f32>" && 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<f32>",
test: (data) => data.type === "vec4<f32>" && 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<f32>",
test: (data) => data.type === "vec3<f32>" && 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$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));
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<f32>": `
data[offset] = v[0];
data[offset + 1] = v[1];`,
"vec3<f32>": `
data[offset] = v[0];
data[offset + 1] = v[1];
data[offset + 2] = v[2];`,
"vec4<f32>": `
data[offset] = v[0];
data[offset + 1] = v[1];
data[offset + 2] = v[2];
data[offset + 3] = v[3];`,
"mat2x2<f32>": `
data[offset] = v[0];
data[offset + 1] = v[1];
data[offset + 4] = v[2];
data[offset + 5] = v[3];`,
"mat3x3<f32>": `
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<f32>": `
for (let i = 0; i < 16; i++) {
data[offset + i] = v[i];
}`,
"mat3x2<f32>": loopMatrix(3, 2),
"mat4x2<f32>": loopMatrix(4, 2),
"mat2x3<f32>": loopMatrix(2, 3),
"mat4x3<f32>": loopMatrix(4, 3),
"mat2x4<f32>": loopMatrix(2, 4),
"mat3x4<f32>": loopMatrix(3, 4)
};
const uboSyncFunctionsWGSL = __spreadProps$8(__spreadValues$j({}, uboSyncFunctionsSTD40), {
"mat2x2<f32>": `
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();
const colorTexture = renderTarget.colorTexture;
if (CanvasSource.test(colorTexture.resource)) {
this._renderer.context.ensureCanvasSize(renderTarget.colorTexture.resource);
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 || renderTarget.depth) {
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
);
}
}
postrender(renderTarget) {
if (!this._renderer.context.multiView)
return;
if (CanvasSource.test(renderTarget.colorTexture.resource)) {
const contextCanvas = this._renderer.context.canvas;
const canvasSource = renderTarget.colorTexture;
canvasSource.context2D.drawImage(
contextCanvas,
0,
canvasSource.pixelHeight - contextCanvas.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$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 canvasCache = /* @__PURE__ */ new Map();
function getCanvasTexture(canvas, options) {
if (!canvasCache.has(canvas)) {
const texture = new Texture({
source: new CanvasSource(__spreadValues$i({
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$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 _RenderTarget = class _RenderTarget {
/**
* @param [descriptor] - Options for creating a render target.
*/
constructor(descriptor = {}) {
/** unique id for this render target */
this.uid = uid$1("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$h(__spreadValues$h({}, _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);
}
postrender() {
var _a, _b;
(_b = (_a = this.adaptor).postrender) == null ? void 0 : _b.call(_a, 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();
this._renderSurfaceToRenderTargetHash.delete(renderSurface);
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 */
this.uid = uid$1("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$1("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$1("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._shaderSyncFunctions = /* @__PURE__ */ Object.create(null);
this._activeProgram = null;
this.maxTextures = getMaxTexturesPerBatch();
}
/**
* 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<f32>": `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<f32>": `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<f32>": `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<i32>": `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<i32>": `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<i32>": `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<u32>": `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<u32>": `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<u32>": `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<bool>": `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<bool>": `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<bool>": `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<f32>": `gl.uniformMatrix2fv(location, false, v);`,
"mat3x3<f32>": `gl.uniformMatrix3fv(location, false, v);`,
"mat4x4<f32>": `gl.uniformMatrix4fv(location, false, v);`
};
const UNIFORM_TO_ARRAY_SETTERS = {
f32: `gl.uniform1fv(location, v);`,
"vec2<f32>": `gl.uniform2fv(location, v);`,
"vec3<f32>": `gl.uniform3fv(location, v);`,
"vec4<f32>": `gl.uniform4fv(location, v);`,
"mat2x2<f32>": `gl.uniformMatrix2fv(location, false, v);`,
"mat3x3<f32>": `gl.uniformMatrix3fv(location, false, v);`,
"mat4x4<f32>": `gl.uniformMatrix4fv(location, false, v);`,
i32: `gl.uniform1iv(location, v);`,
"vec2<i32>": `gl.uniform2iv(location, v);`,
"vec3<i32>": `gl.uniform3iv(location, v);`,
"vec4<i32>": `gl.uniform4iv(location, v);`,
u32: `gl.uniform1iv(location, v);`,
"vec2<u32>": `gl.uniform2iv(location, v);`,
"vec3<u32>": `gl.uniform3iv(location, v);`,
"vec4<u32>": `gl.uniform4iv(location, v);`,
bool: `gl.uniform1iv(location, v);`,
"vec2<bool>": `gl.uniform2iv(location, v);`,
"vec3<bool>": `gl.uniform3iv(location, v);`,
"vec4<bool>": `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);
}
}
/**
* Overridable 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];
const isWebGl2 = !(gl instanceof DOMAdapter.get().getWebGLRenderingContext());
if (isWebGl2) {
blendMap.min = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, gl.MIN, gl.MIN];
blendMap.max = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, gl.MAX, gl.MAX];
} else {
const ext = gl.getExtension("EXT_blend_minmax");
if (ext) {
blendMap.min = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, ext.MIN_EXT, ext.MIN_EXT];
blendMap.max = [gl.ONE, gl.ONE, gl.ONE, gl.ONE, ext.MAX_EXT, ext.MAX_EXT];
}
}
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$g = Object.defineProperty;
var __defProps$7 = Object.defineProperties;
var __getOwnPropDescs$7 = 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$7 = (a, b) => __defProps$7(a, __getOwnPropDescs$7(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$g(__spreadValues$g(__spreadValues$g(__spreadValues$g(__spreadValues$g(__spreadValues$g(__spreadProps$7(__spreadValues$g({
// 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<f32>" },
uTransformMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
uRound: { value: 0, type: "f32" }
});
const maxTextures = getMaxTexturesPerBatch();
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 {
batcher,
instructions
} = contextSystem.getContextRenderData(context);
shader.groups[0] = renderer.globalUniforms.bindGroup;
renderer.state.set(graphicsPipe.state);
renderer.shader.bind(shader);
renderer.geometry.bind(batcher.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.count; 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<f32>", 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 clearList(list, index) {
index || (index = 0);
for (let j = index; j < list.length; j++) {
if (list[j]) {
list[j] = null;
} else {
break;
}
}
}
"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();
const UPDATE_BLEND_COLOR_VISIBLE = UPDATE_VISIBLE | UPDATE_COLOR | UPDATE_BLEND;
function updateRenderGroupTransforms(renderGroup, updateChildRenderGroups = false) {
updateRenderGroupTransform(renderGroup);
const childrenToUpdate = renderGroup.childrenToUpdate;
const updateTick = renderGroup.updateTick++;
for (const j in childrenToUpdate) {
const renderGroupDepth = Number(j);
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 && child.relativeRenderGroupDepth === renderGroupDepth) {
updateTransformAndChildren(child, updateTick, 0);
}
}
clearList(list, index);
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 & UPDATE_BLEND_COLOR_VISIBLE) {
updateColorBlendVisibility(container, parent, updateFlags);
}
} else {
updateFlags = container._updateFlags;
container.relativeGroupTransform.copyFrom(localTransform);
if (updateFlags & UPDATE_BLEND_COLOR_VISIBLE) {
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$1 = 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$1;
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);
} else {
clearList(renderGroup.childrenRenderablesToUpdate.list, 0);
}
updateRenderGroupTransforms(renderGroup);
if (renderGroup.structureDidChange) {
renderGroup.structureDidChange = false;
buildInstructions(renderGroup, renderer);
} 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);
}
}
clearList(list, index);
}
"use strict";
class SpritePipe {
constructor(renderer) {
this._gpuSpriteHash = /* @__PURE__ */ Object.create(null);
this._destroyRenderableBound = this.destroyRenderable.bind(this);
this._renderer = renderer;
}
addRenderable(sprite, instructionSet) {
const gpuSprite = this._getGpuSprite(sprite);
if (sprite._didSpriteUpdate)
this._updateBatchableSprite(sprite, gpuSprite);
this._renderer.renderPipes.batch.addToBatch(gpuSprite, instructionSet);
}
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;
sprite.off("destroyed", this._destroyRenderableBound);
}
_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.transform = sprite.groupTransform;
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._destroyRenderableBound);
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$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 _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$f(__spreadValues$f({}, _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$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 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$e({
target: options
}, defaults);
}
return __spreadValues$e(__spreadValues$e({}, 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 RenderTexture({
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$d = Object.defineProperty;
var __defProps$6 = Object.defineProperties;
var __getOwnPropDescs$6 = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$6 = (a, b) => __defProps$6(a, __getOwnPropDescs$6(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$6(__spreadValues$d({}, 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
});
target.source.updateMipmaps();
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<f32>" },
uWorldTransformMatrix: { value: new Matrix(), type: "mat3x3<f32>" },
// TODO - someone smart - set this to be a unorm8x4 rather than a vec4<f32>
uWorldColorAlpha: { value: new Float32Array(4), type: "vec4<f32>" },
uResolution: { value: [0, 0], type: "vec2<f32>" }
}, {
isStatic: true
});
return globalUniforms;
}
destroy() {
this._renderer = null;
}
}
/** @ignore */
GlobalUniformSystem.extension = {
type: [
ExtensionType.WebGLSystem,
ExtensionType.WebGPUSystem,
ExtensionType.CanvasSystem
],
name: "globalUniforms"
};
"use strict";
let uid = 1;
class SchedulerSystem {
constructor() {
this._tasks = [];
}
/** Initializes the scheduler system and starts the ticker. */
init() {
Ticker.system.add(this._update, this);
}
/**
* Schedules a repeating task.
* @param func - The function to execute.
* @param duration - The interval duration in milliseconds.
* @returns The unique identifier for the scheduled task.
*/
repeat(func, duration) {
const id = uid++;
this._tasks.push({
func,
duration,
start: performance.now(),
last: performance.now(),
repeat: true,
id
});
return id;
}
/**
* Cancels a scheduled task.
* @param id - The unique identifier of the task to cancel.
*/
cancel(id) {
for (let i = 0; i < this._tasks.length; i++) {
if (this._tasks[i].id === id) {
this._tasks.splice(i, 1);
return;
}
}
}
/**
* Updates and executes the scheduled tasks.
* @private
*/
_update() {
const now = performance.now();
for (let i = 0; i < this._tasks.length; i++) {
const task = this._tasks[i];
if (now - task.last >= task.duration) {
const elapsed = now - task.start;
task.func(elapsed);
task.last = now;
}
}
}
/**
* Destroys the scheduler system and removes all tasks.
* @internal
* @ignore
*/
destroy() {
Ticker.system.remove(this._update, this);
this._tasks.length = 0;
}
}
/** @ignore */
SchedulerSystem.extension = {
type: [
ExtensionType.WebGLSystem,
ExtensionType.WebGPUSystem,
ExtensionType.CanvasSystem
],
name: "scheduler",
priority: 0
};
"use strict";
let saidHello = false;
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$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 _RenderableGCSystem = class _RenderableGCSystem {
/** @param renderer - The renderer this System works for. */
constructor(renderer) {
this._managedRenderables = [];
this._renderer = renderer;
}
init(options) {
options = __spreadValues$c(__spreadValues$c({}, _RenderableGCSystem.defaultOptions), options);
this.maxUnusedTime = options.renderableGCMaxUnusedTime;
this._frequency = options.renderableGCFrequency;
this.enabled = options.renderableGCActive;
}
get enabled() {
return !!this._handler;
}
set enabled(value) {
if (this.enabled === value)
return;
if (value) {
this._handler = this._renderer.scheduler.repeat(
() => this.run(),
this._frequency
);
} else {
this._renderer.scheduler.cancel(this._handler);
}
}
prerender() {
this._now = performance.now();
}
addRenderable(renderable, instructionSet) {
if (!this.enabled)
return;
renderable._lastUsed = this._now;
if (renderable._lastInstructionTick === -1) {
this._managedRenderables.push(renderable);
renderable.once("destroyed", this._removeRenderable, this);
}
renderable._lastInstructionTick = instructionSet.tick;
}
/** Runs the scheduled garbage collection */
run() {
var _a, _b, _c;
const now = performance.now();
const managedRenderables = this._managedRenderables;
const renderPipes = this._renderer.renderPipes;
let offset = 0;
for (let i = 0; i < managedRenderables.length; i++) {
const renderable = managedRenderables[i];
if (renderable === null) {
offset++;
continue;
}
const renderGroup = (_a = renderable.renderGroup) != null ? _a : renderable.parentRenderGroup;
const currentIndex = (_c = (_b = renderGroup == null ? void 0 : renderGroup.instructionSet) == null ? void 0 : _b.tick) != null ? _c : -1;
if (renderable._lastInstructionTick !== currentIndex && now - renderable._lastUsed > this.maxUnusedTime) {
if (!renderable.destroyed) {
const rp = renderPipes;
rp[renderable.renderPipeId].destroyRenderable(renderable);
}
renderable._lastInstructionTick = -1;
offset++;
renderable.off("destroyed", this._removeRenderable, this);
} else {
managedRenderables[i - offset] = renderable;
}
}
managedRenderables.length = managedRenderables.length - offset;
}
destroy() {
this.enabled = false;
this._renderer = null;
this._managedRenderables.length = 0;
}
_removeRenderable(renderable) {
const index = this._managedRenderables.indexOf(renderable);
if (index >= 0) {
renderable.off("destroyed", this._removeRenderable, this);
this._managedRenderables[index] = null;
}
}
};
/** @ignore */
_RenderableGCSystem.extension = {
type: [
ExtensionType.WebGLSystem,
ExtensionType.WebGPUSystem
],
name: "renderableGC"
};
/** default options for the renderableGCSystem */
_RenderableGCSystem.defaultOptions = {
/**
* If set to true, this will enable the garbage collector on the GPU.
* @default true
*/
renderableGCActive: true,
/**
* The maximum idle frames before a texture is destroyed by garbage collection.
* @default 60 * 60
*/
renderableGCMaxUnusedTime: 6e4,
/**
* Frames between two garbage collections.
* @default 600
*/
renderableGCFrequency: 3e4
};
let RenderableGCSystem = _RenderableGCSystem;
"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 _TextureGCSystem = class _TextureGCSystem {
/** @param renderer - The renderer this System works for. */
constructor(renderer) {
this._renderer = renderer;
this.count = 0;
this.checkCount = 0;
}
init(options) {
var _a;
options = __spreadValues$b(__spreadValues$b({}, _TextureGCSystem.defaultOptions), options);
this.checkCountMax = options.textureGCCheckCountMax;
this.maxIdle = (_a = options.textureGCAMaxIdle) != null ? _a : options.textureGCMaxIdle;
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,
/**
* @deprecated since 8.3.0
* @see {@link TextureGCSystem.textureGCMaxIdle}
*/
textureGCAMaxIdle: null,
/**
* The maximum idle frames before a texture is destroyed by garbage collection.
* @default 60 * 60
*/
textureGCMaxIdle: 60 * 60,
/**
* Frames between two garbage collections.
* @default 600
*/
textureGCCheckCountMax: 600
};
let TextureGCSystem = _TextureGCSystem;
"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 _ViewSystem = class _ViewSystem {
/**
* Whether CSS dimensions of canvas view should be resized to screen dimensions automatically.
* @member {boolean}
*/
get autoDensity() {
return this.texture.source.autoDensity;
}
set autoDensity(value) {
this.texture.source.autoDensity = value;
}
/** 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$a(__spreadValues$a({}, _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.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;
}
/**
* 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,
RendererInitHook,
RenderableGCSystem,
SchedulerSystem
];
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);
this._managedBuffers.push(buffer);
}
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;
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 DOMAdapter.get().getNavigator().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$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;
};
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, program) {
const buffersToBind = this._renderer.pipeline.getBufferNamesToBind(geometry, program);
for (const i in buffersToBind) {
this._setVertexBuffer(i, geometry.attributes[buffersToBind[i]].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, shader.gpuProgram);
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$9({}, this._boundVertexBuffer);
const boundIndexBuffer = this._boundIndexBuffer;
const boundBindGroup = __spreadValues$9({}, 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<i32>": { align: 8, size: 8 },
"vec2<u32>": { align: 8, size: 8 },
"vec2<f32>": { align: 8, size: 8 },
"vec2<f16>": { align: 4, size: 4 },
"vec3<i32>": { align: 16, size: 12 },
"vec3<u32>": { align: 16, size: 12 },
"vec3<f32>": { align: 16, size: 12 },
"vec3<f16>": { align: 8, size: 6 },
"vec4<i32>": { align: 16, size: 16 },
"vec4<u32>": { align: 16, size: 16 },
"vec4<f32>": { align: 16, size: 16 },
"vec4<f16>": { align: 8, size: 8 },
"mat2x2<f32>": { align: 8, size: 16 },
"mat2x2<f16>": { align: 4, size: 8 },
"mat3x2<f32>": { align: 8, size: 24 },
"mat3x2<f16>": { align: 4, size: 12 },
"mat4x2<f32>": { align: 8, size: 32 },
"mat4x2<f16>": { align: 4, size: 16 },
"mat2x3<f32>": { align: 16, size: 32 },
"mat2x3<f16>": { align: 8, size: 16 },
"mat3x3<f32>": { align: 16, size: 48 },
"mat3x3<f16>": { align: 8, size: 24 },
"mat4x3<f32>": { align: 16, size: 64 },
"mat4x3<f16>": { align: 8, size: 32 },
"mat2x4<f32>": { align: 16, size: 32 },
"mat2x4<f16>": { align: 8, size: 16 },
"mat3x4<f32>": { align: 16, size: 48 },
"mat3x4<f16>": { align: 8, size: 24 },
"mat4x4<f32>": { align: 16, size: 64 },
"mat4x4<f16>": { 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$8 = Object.defineProperty;
var __defProps$5 = Object.defineProperties;
var __getOwnPropDescs$5 = Object.getOwnPropertyDescriptors;
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;
};
var __spreadProps$5 = (a, b) => __defProps$5(a, __getOwnPropDescs$5(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._bindingNamesCache = /* @__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, program);
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$5(__spreadValues$8({}, 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.offset;
keyGen[index++] = attribute.format;
keyGen[index++] = attribute.stride;
keyGen[index++] = attribute.instance;
}
const stringKey = keyGen.join("|");
geometry._layoutKey = createIdFromString(stringKey, "geometry");
return geometry._layoutKey;
}
_generateAttributeLocationsKey(program) {
const keyGen = [];
let index = 0;
const attributeKeys = Object.keys(program.attributeData).sort();
for (let i = 0; i < attributeKeys.length; i++) {
const attribute = program.attributeData[attributeKeys[i]];
keyGen[index++] = attribute.location;
}
const stringKey = keyGen.join("|");
program._attributeLocationsKey = createIdFromString(stringKey, "programAttributes");
return program._attributeLocationsKey;
}
/**
* Returns a hash of buffer names mapped to bind locations.
* This is used to bind the correct buffer to the correct location in the shader.
* @param geometry - The geometry where to get the buffer names
* @param program - The program where to get the buffer names
* @returns An object of buffer names mapped to the bind location.
*/
getBufferNamesToBind(geometry, program) {
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bindingNamesCache[key])
return this._bindingNamesCache[key];
const data = this._createVertexBufferLayouts(geometry, program);
const bufferNamesToBind = /* @__PURE__ */ Object.create(null);
const attributeData = program.attributeData;
for (let i = 0; i < data.length; i++) {
for (const j in attributeData) {
if (attributeData[j].location === i) {
bufferNamesToBind[i] = j;
break;
}
}
}
this._bindingNamesCache[key] = bufferNamesToBind;
return bufferNamesToBind;
}
_createVertexBufferLayouts(geometry, program) {
if (!program._attributeLocationsKey)
this._generateAttributeLocationsKey(program);
const key = geometry._layoutKey << 16 | program._attributeLocationsKey;
if (this._bufferLayoutsCache[key]) {
return this._bufferLayoutsCache[key];
}
const vertexBuffersLayout = [];
geometry.buffers.forEach((buffer) => {
var _a;
const bufferEntry = {
arrayStride: 0,
stepMode: "vertex",
attributes: []
};
const bufferEntryAttributes = bufferEntry.attributes;
for (const i in program.attributeData) {
const attribute = geometry.attributes[i];
if (((_a = attribute.divisor) != null ? _a : 1) !== 1) {
warn(`Attribute ${i} has an invalid divisor value of '${attribute.divisor}'. WebGPU only supports a divisor value of 1`);
}
if (attribute.buffer === buffer) {
bufferEntry.arrayStride = attribute.stride;
bufferEntry.stepMode = attribute.instance ? "instance" : "vertex";
bufferEntryAttributes.push({
shaderLocation: program.attributeData[i].location,
offset: attribute.offset,
format: attribute.format
});
}
}
if (bufferEntryAttributes.length) {
vertexBuffersLayout.push(bufferEntry);
}
});
this._bufferLayoutsCache[key] = 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;
this.maxTextures = gpu.device.limits.maxSampledTexturesPerShaderStage;
}
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"
}
};
GpuBlendModesToPixi.min = {
alpha: {
srcFactor: "one",
dstFactor: "one",
operation: "min"
},
color: {
srcFactor: "one",
dstFactor: "one",
operation: "min"
}
};
GpuBlendModesToPixi.max = {
alpha: {
srcFactor: "one",
dstFactor: "one",
operation: "max"
},
color: {
srcFactor: "one",
dstFactor: "one",
operation: "max"
}
};
"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<private> pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 3.0), vec2<f32>(3.0, -1.0));
struct VertexOutput {
@builtin(position) position : vec4<f32>,
@location(0) texCoord : vec2<f32>,
};
@vertex
fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
var output : VertexOutput;
output.texCoord = pos[vertexIndex] * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
return output;
}
@group(0) @binding(0) var imgSampler : sampler;
@group(0) @binding(1) var img : texture_2d<f32>;
@fragment
fn fragmentMain(@location(0) texCoord : vec2<f32>) -> @location(0) vec4<f32> {
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);
}
/**
* this returns s bind group for a specific texture, the bind group contains
* - the texture source
* - the texture style
* - the texture matrix
* This is cached so the bind group should only be created once per texture
* @param texture - the texture you want the bindgroup for
* @returns the bind group for the texture
*/
getTextureBindGroup(texture) {
var _a;
return (_a = this._bindGroupHash[texture.uid]) != null ? _a : this._createTextureBindGroup(texture);
}
_createTextureBindGroup(texture) {
const source = texture.source;
this._bindGroupHash[texture.uid] = new BindGroup({
0: source,
1: source.style,
2: new UniformGroup({
uTextureMatrix: { type: "mat3x3<f32>", value: texture.textureMatrix.mapCoord }
})
});
return this._bindGroupHash[texture.uid];
}
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: DOMAdapter.get().getNavigator().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<f32>" },
uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
uRound: { value: 0, type: "f32" }
});
const gpuProgram = compileHighShaderGpuProgram({
name: "graphics",
bits: [
colorBit,
generateTextureBatchBit(getMaxTexturesPerBatch()),
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 {
batcher,
instructions
} = contextSystem.getContextRenderData(context);
const encoder = renderer.encoder;
encoder.setPipelineFromGeometryProgramAndState(
batcher.geometry,
shader.gpuProgram,
graphicsPipe.state
);
encoder.setGeometry(batcher.geometry, shader.gpuProgram);
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<f32>", value: new Matrix() }
}
}
});
}
execute(meshPipe, mesh) {
const renderer = meshPipe.renderer;
let shader = mesh._shader;
if (!shader) {
shader = this._shader;
shader.groups[2] = renderer.texture.getTextureBindGroup(mesh.texture);
} 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";
"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$7 = Object.defineProperty;
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 __objRest$5 = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$7.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$7)
for (var prop of __getOwnPropSymbols$7(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$7.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$5(_a, ["render"]);
super(__spreadValues$7({
label: "RenderContainer"
}, rest));
this.batched = false;
this._lastUsed = 0;
this._lastInstructionTick = -1;
/**
* 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 overridable 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";
function applyProjectiveTransformationToPlane(width, height, geometry, transformationMatrix) {
const buffer = geometry.buffers[0];
const vertices = buffer.data;
const { verticesX, verticesY } = geometry;
const sizeX = width / (verticesX - 1);
const sizeY = height / (verticesY - 1);
let index = 0;
const a00 = transformationMatrix[0];
const a01 = transformationMatrix[1];
const a02 = transformationMatrix[2];
const a10 = transformationMatrix[3];
const a11 = transformationMatrix[4];
const a12 = transformationMatrix[5];
const a20 = transformationMatrix[6];
const a21 = transformationMatrix[7];
const a22 = transformationMatrix[8];
for (let i = 0; i < vertices.length; i += 2) {
const x = index % verticesX * sizeX;
const y = (index / verticesX | 0) * sizeY;
const newX = a00 * x + a01 * y + a02;
const newY = a10 * x + a11 * y + a12;
const w = a20 * x + a21 * y + a22;
vertices[i] = newX / w;
vertices[i + 1] = newY / w;
index++;
}
buffer.update();
}
"use strict";
function computeAdjugate(out, matrix) {
const a00 = matrix[0];
const a01 = matrix[1];
const a02 = matrix[2];
const a10 = matrix[3];
const a11 = matrix[4];
const a12 = matrix[5];
const a20 = matrix[6];
const a21 = matrix[7];
const a22 = matrix[8];
out[0] = a11 * a22 - a12 * a21;
out[1] = a02 * a21 - a01 * a22;
out[2] = a01 * a12 - a02 * a11;
out[3] = a12 * a20 - a10 * a22;
out[4] = a00 * a22 - a02 * a20;
out[5] = a02 * a10 - a00 * a12;
out[6] = a10 * a21 - a11 * a20;
out[7] = a01 * a20 - a00 * a21;
out[8] = a00 * a11 - a01 * a10;
return out;
}
function multiplyMatrix3x3(out, a, b) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
const b00 = b[0];
const b01 = b[1];
const b02 = b[2];
const b10 = b[3];
const b11 = b[4];
const b12 = b[5];
const b20 = b[6];
const b21 = b[7];
const b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
}
function multiplyMatrixAndVector(out, m, v) {
const x = v[0];
const y = v[1];
const z = v[2];
out[0] = m[0] * x + m[1] * y + m[2] * z;
out[1] = m[3] * x + m[4] * y + m[5] * z;
out[2] = m[6] * x + m[7] * y + m[8] * z;
return out;
}
const tempMatrix = [0, 0, 0, 0, 0, 0, 0, 0, 0];
const tempVec = [0, 0, 0];
const tempVec2 = [0, 0, 0];
function generateBasisToPointsMatrix(out, x1, y1, x2, y2, x3, y3, x4, y4) {
const m = tempMatrix;
m[0] = x1;
m[1] = x2;
m[2] = x3;
m[3] = y1;
m[4] = y2;
m[5] = y3;
m[6] = 1;
m[7] = 1;
m[8] = 1;
const adjugateM = computeAdjugate(
out,
// reusing out as adjugateM is only used once
m
);
tempVec2[0] = x4;
tempVec2[1] = y4;
tempVec2[2] = 1;
const v = multiplyMatrixAndVector(
tempVec,
adjugateM,
tempVec2
);
const diagonalMatrix = out;
out[0] = v[0];
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = v[1];
out[5] = 0;
out[6] = 0;
out[7] = 0;
out[8] = v[2];
return multiplyMatrix3x3(out, diagonalMatrix, m);
}
const tempSourceMatrix = [0, 0, 0, 0, 0, 0, 0, 0, 0];
const tempDestinationMatrix = [0, 0, 0, 0, 0, 0, 0, 0, 0];
function compute2DProjection(out, x1s, y1s, x1d, y1d, x2s, y2s, x2d, y2d, x3s, y3s, x3d, y3d, x4s, y4s, x4d, y4d) {
const sourceMatrix = generateBasisToPointsMatrix(
tempSourceMatrix,
x1s,
y1s,
x2s,
y2s,
x3s,
y3s,
x4s,
y4s
);
const destinationMatrix = generateBasisToPointsMatrix(
tempDestinationMatrix,
x1d,
y1d,
x2d,
y2d,
x3d,
y3d,
x4d,
y4d
);
return multiplyMatrix3x3(
out,
computeAdjugate(sourceMatrix, sourceMatrix),
destinationMatrix
);
}
"use strict";
class PerspectivePlaneGeometry extends PlaneGeometry {
/**
* @param options - Options to be applied to MeshPlane
* @param options.width - The width of the plane
* @param options.height - The height of the plane
* @param options.verticesX - The amount of vertices on the x axis
* @param options.verticesY - The amount of vertices on the y axis
*/
constructor(options) {
super(options);
this._projectionMatrix = [0, 0, 0, 0, 0, 0, 0, 0, 0];
const { width, height } = options;
this.corners = [0, 0, width, 0, width, height, 0, height];
}
/**
* Will set the corners of the quad to the given coordinates
* Calculating the perspective so it looks correct!
* @param x0 - x coordinate of the first corner
* @param y0 - y coordinate of the first corner
* @param x1 - x coordinate of the second corner
* @param y1 - y coordinate of the second corner
* @param x2 - x coordinate of the third corner
* @param y2 - y coordinate of the third corner
* @param x3 - x coordinate of the fourth corner
* @param y3 - y coordinate of the fourth corner
*/
setCorners(x0, y0, x1, y1, x2, y2, x3, y3) {
const corners = this.corners;
corners[0] = x0;
corners[1] = y0;
corners[2] = x1;
corners[3] = y1;
corners[4] = x2;
corners[5] = y2;
corners[6] = x3;
corners[7] = y3;
this.updateProjection();
}
/** Update the projection matrix based on the corners */
updateProjection() {
const { width, height } = this;
const corners = this.corners;
const projectionMatrix = compute2DProjection(
this._projectionMatrix,
0,
0,
// top-left source
corners[0],
corners[1],
// top-left dest
width,
0,
// top-right source
corners[2],
corners[3],
// top-right dest
width,
height,
// bottom-right source
corners[4],
corners[5],
// bottom-right dest
0,
height,
// bottom-left source
corners[6],
corners[7]
// bottom-left dest
);
applyProjectiveTransformationToPlane(
width,
height,
this,
projectionMatrix
);
}
}
"use strict";
var __defProp$6 = Object.defineProperty;
var __defProps$4 = Object.defineProperties;
var __getOwnPropDescs$4 = Object.getOwnPropertyDescriptors;
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 __spreadProps$4 = (a, b) => __defProps$4(a, __getOwnPropDescs$4(b));
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;
};
const _PerspectiveMesh = class _PerspectiveMesh extends Mesh {
/**
* @param options - Options to be applied to PerspectiveMesh
*/
constructor(options) {
options = __spreadValues$6(__spreadValues$6({}, _PerspectiveMesh.defaultOptions), options);
const _a = options, { texture, verticesX, verticesY } = _a, rest = __objRest$4(_a, ["texture", "verticesX", "verticesY"]);
const planeGeometry = new PerspectivePlaneGeometry(definedProps({
width: texture.width,
height: texture.height,
verticesX,
verticesY
}));
super(definedProps(__spreadProps$4(__spreadValues$6({}, rest), { geometry: planeGeometry })));
this._texture = texture;
this.geometry.setCorners(
options.x0,
options.y0,
options.x1,
options.y1,
options.x2,
options.y2,
options.x3,
options.y3
);
}
/** Update the geometry when the texture is updated */
textureUpdated() {
const geometry = this.geometry;
if (!geometry)
return;
const { width, height } = this.texture;
if (geometry.width !== width || geometry.height !== height) {
geometry.width = width;
geometry.height = height;
geometry.updateProjection();
}
}
set texture(value) {
if (this._texture === value)
return;
super.texture = value;
this.textureUpdated();
}
/** The texture that the mesh uses */
get texture() {
return this._texture;
}
/**
* Set the corners of the quad to the given coordinates
* The mesh will then calculate the perspective so it looks correct!
* @param x0 - x coordinate of the first corner
* @param y0 - y coordinate of the first corner
* @param x1 - x coordinate of the second corner
* @param y1 - y coordinate of the second corner
* @param x2 - x coordinate of the third corner
* @param y2 - y coordinate of the third corner
* @param x3 - x coordinate of the fourth corner
* @param y3 - y coordinate of the fourth corner
*/
setCorners(x0, y0, x1, y1, x2, y2, x3, y3) {
this.geometry.setCorners(x0, y0, x1, y1, x2, y2, x3, y3);
}
};
/** default options for the mesh */
_PerspectiveMesh.defaultOptions = {
texture: Texture.WHITE,
verticesX: 10,
verticesY: 10,
x0: 0,
y0: 0,
x1: 100,
y1: 0,
x2: 100,
y2: 100,
x3: 0,
y3: 100
};
let PerspectiveMesh = _PerspectiveMesh;
"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 ViewContainer {
/**
* @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.renderPipeId = "nineSliceSprite";
this.batched = true;
this._didSpriteUpdate = true;
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 local bounds of the view. */
get bounds() {
return this._bounds;
}
/** 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();
}
/**
* Sets the size of the NiceSliceSprite to the specified width and height.
* setting this will actually modify the vertices and UV's of this plane
* 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;
if (typeof value === "object") {
height = (_a = value.height) != null ? _a : value.width;
value = value.width;
}
this.bounds.maxX = this._width = value;
this.bounds.maxY = this._height = height != null ? height : value;
this.onViewUpdate();
}
/**
* Retrieves the size of the NineSliceSprite 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 NineSliceSprite.
*/
getSize(out) {
out || (out = {});
out.width = this._width;
out.height = this._height;
return out;
}
/** 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();
}
/** 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._didViewChangeTick++;
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);
}
/**
* 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;
}
};
/** 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";
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.ApplicationInitHook = ApplicationInitHook;
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.DefaultBatcher = DefaultBatcher;
exports.DefaultShader = DefaultShader;
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.PerspectiveMesh = PerspectiveMesh;
exports.PerspectivePlaneGeometry = PerspectivePlaneGeometry;
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.RenderableGCSystem = RenderableGCSystem;
exports.RendererInitHook = RendererInitHook;
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.SchedulerSystem = SchedulerSystem;
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.ViewContainer = ViewContainer;
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.applyProjectiveTransformationToPlane = applyProjectiveTransformationToPlane;
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.buildEllipse = buildEllipse;
exports.buildGeometryFromPath = buildGeometryFromPath;
exports.buildInstructions = buildInstructions;
exports.buildLine = buildLine;
exports.buildPolygon = buildPolygon;
exports.buildRectangle = buildRectangle;
exports.buildRoundedRectangle = buildRoundedRectangle;
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.checkMaxIfStatementsInShader = checkMaxIfStatementsInShader;
exports.childrenHelperMixin = childrenHelperMixin;
exports.clearList = clearList;
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.compute2DProjection = compute2DProjection;
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.getMaxTexturesPerBatch = getMaxTexturesPerBatch;
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.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.shapeBuilders = shapeBuilders;
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$1;
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.v8_3_4 = v8_3_4;
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