wave-roll
Version:
JavaScript Library for Comparative MIDI Piano-Roll Visualization
1,356 lines (1,353 loc) • 90.9 kB
JavaScript
import { E as m, U as it, T as de, a as nt, a1 as T, a2 as B, t as w, ab as ce, Z as W, ac as D, O as at, l as V, ad as ot, ae as he, _ as Te, af as I, ag as P, w as te, k as z, c as we, H as C, M as U, a4 as re, R as se, F as Se, b as O, B as F, D as ie, y as Y, ah as lt, ai as ne, K as J, aj as E, s as ae, u as ut, G as dt, m as Pe, q as Ce, a6 as Fe, a9 as Be, n as ct, o as ht, a7 as ft, a8 as pt, aa as gt, ak as mt, al as xt, am as $, e as v, an as _t } from "./index-Bn89Sr5W.js";
import { S as X, c as j, a as bt, b as yt, B as Ue } from "./colorToUniform-zJcCVLeu.js";
class Me {
/**
* Initialize the plugin with scope of application instance
* @private
* @param {object} [options] - See application options
*/
static init(e) {
Object.defineProperty(
this,
"resizeTo",
{
set(t) {
globalThis.removeEventListener("resize", this.queueResize), this._resizeTo = t, t && (globalThis.addEventListener("resize", this.queueResize), this.resize());
},
get() {
return this._resizeTo;
}
}
), this.queueResize = () => {
this._resizeTo && (this._cancelResize(), this._resizeId = requestAnimationFrame(() => this.resize()));
}, this._cancelResize = () => {
this._resizeId && (cancelAnimationFrame(this._resizeId), this._resizeId = null);
}, this.resize = () => {
if (!this._resizeTo)
return;
this._cancelResize();
let t, r;
if (this._resizeTo === globalThis.window)
t = globalThis.innerWidth, r = globalThis.innerHeight;
else {
const { clientWidth: s, clientHeight: i } = this._resizeTo;
t = s, r = i;
}
this.renderer.resize(t, r), this.render();
}, this._resizeId = null, this._resizeTo = null, this.resizeTo = e.resizeTo || null;
}
/**
* Clean up the ticker, scoped to application
* @private
*/
static destroy() {
globalThis.removeEventListener("resize", this.queueResize), this._cancelResize(), this._cancelResize = null, this.queueResize = null, this.resizeTo = null, this.resize = null;
}
}
Me.extension = m.Application;
class Re {
/**
* Initialize the plugin with scope of application instance
* @private
* @param {object} [options] - See application options
*/
static init(e) {
e = Object.assign({
autoStart: !0,
sharedTicker: !1
}, e), Object.defineProperty(
this,
"ticker",
{
set(t) {
this._ticker && this._ticker.remove(this.render, this), this._ticker = t, t && t.add(this.render, this, it.LOW);
},
get() {
return this._ticker;
}
}
), this.stop = () => {
this._ticker.stop();
}, this.start = () => {
this._ticker.start();
}, this._ticker = null, this.ticker = e.sharedTicker ? de.shared : new de(), e.autoStart && this.start();
}
/**
* Clean up the ticker, scoped to application.
* @private
*/
static destroy() {
if (this._ticker) {
const e = this._ticker;
this.ticker = null, e.destroy();
}
}
}
Re.extension = m.Application;
class vt extends nt {
constructor() {
super(...arguments), this.chars = /* @__PURE__ */ Object.create(null), this.lineHeight = 0, this.fontFamily = "", this.fontMetrics = { fontSize: 0, ascent: 0, descent: 0 }, this.baseLineOffset = 0, this.distanceField = { type: "none", range: 0 }, this.pages = [], this.applyFillAsTint = !0, this.baseMeasurementFontSize = 100, this.baseRenderedFontSize = 100;
}
/**
* The name of the font face.
* @deprecated since 8.0.0 Use `fontFamily` instead.
*/
get font() {
return T(B, "BitmapFont.font is deprecated, please use BitmapFont.fontFamily instead."), this.fontFamily;
}
/**
* The map of base page textures (i.e., sheets of glyphs).
* @deprecated since 8.0.0 Use `pages` instead.
*/
get pageTextures() {
return T(B, "BitmapFont.pageTextures is deprecated, please use BitmapFont.pages instead."), this.pages;
}
/**
* The size of the font face in pixels.
* @deprecated since 8.0.0 Use `fontMetrics.fontSize` instead.
*/
get size() {
return T(B, "BitmapFont.size is deprecated, please use BitmapFont.fontMetrics.fontSize instead."), this.fontMetrics.fontSize;
}
/**
* The kind of distance field for this font or "none".
* @deprecated since 8.0.0 Use `distanceField.type` instead.
*/
get distanceFieldRange() {
return T(B, "BitmapFont.distanceFieldRange is deprecated, please use BitmapFont.distanceField.range instead."), this.distanceField.range;
}
/**
* The range of the distance field in pixels.
* @deprecated since 8.0.0 Use `distanceField.range` instead.
*/
get distanceFieldType() {
return T(B, "BitmapFont.distanceFieldType is deprecated, please use BitmapFont.distanceField.type instead."), this.distanceField.type;
}
destroy(e = !1) {
this.emit("destroy", this), this.removeAllListeners();
for (const t in this.chars)
this.chars[t].texture?.destroy();
this.chars = null, e && (this.pages.forEach((t) => t.texture.destroy(!0)), this.pages = null);
}
}
const Ge = class Ae extends vt {
/**
* @param options - The options for the dynamic bitmap font.
*/
constructor(e) {
super(), this.resolution = 1, this.pages = [], this._padding = 0, this._measureCache = /* @__PURE__ */ Object.create(null), this._currentChars = [], this._currentX = 0, this._currentY = 0, this._currentMaxCharHeight = 0, this._currentPageIndex = -1, this._skipKerning = !1;
const t = { ...Ae.defaultOptions, ...e };
this._textureSize = t.textureSize, this._mipmap = t.mipmap;
const r = t.style.clone();
t.overrideFill && (r._fill.color = 16777215, r._fill.alpha = 1, r._fill.texture = w.WHITE, r._fill.fill = null), this.applyFillAsTint = t.overrideFill;
const s = r.fontSize;
r.fontSize = this.baseMeasurementFontSize;
const i = ce(r);
t.overrideSize ? r._stroke && (r._stroke.width *= this.baseRenderedFontSize / s) : r.fontSize = this.baseRenderedFontSize = s, this._style = r, this._skipKerning = t.skipKerning ?? !1, this.resolution = t.resolution ?? 1, this._padding = t.padding ?? 4, t.textureStyle && (this._textureStyle = t.textureStyle instanceof W ? t.textureStyle : new W(t.textureStyle)), this.fontMetrics = D.measureFont(i), this.lineHeight = r.lineHeight || this.fontMetrics.fontSize || r.fontSize;
}
ensureCharacters(e) {
const t = D.graphemeSegmenter(e).filter((p) => !this._currentChars.includes(p)).filter((p, g, _) => _.indexOf(p) === g);
if (!t.length)
return;
this._currentChars = [...this._currentChars, ...t];
let r;
this._currentPageIndex === -1 ? r = this._nextPage() : r = this.pages[this._currentPageIndex];
let { canvas: s, context: i } = r.canvasAndContext, n = r.texture.source;
const a = this._style;
let l = this._currentX, u = this._currentY, c = this._currentMaxCharHeight;
const d = this.baseRenderedFontSize / this.baseMeasurementFontSize, h = this._padding * d;
let f = !1;
const b = s.width / this.resolution, x = s.height / this.resolution;
for (let p = 0; p < t.length; p++) {
const g = t[p], _ = D.measureText(g, a, s, !1);
_.lineHeight = _.height;
const y = _.width * d, S = Math.ceil((a.fontStyle === "italic" ? 2 : 1) * y), R = _.height * d, M = S + h * 2, G = R + h * 2;
if (f = !1, g !== `
` && g !== "\r" && g !== " " && g !== " " && (f = !0, c = Math.ceil(Math.max(G, c))), l + M > b && (u += c, c = G, l = 0, u + c > x)) {
n.update();
const k = this._nextPage();
s = k.canvasAndContext.canvas, i = k.canvasAndContext.context, n = k.texture.source, l = 0, u = 0, c = 0;
}
const A = y / d - (a.dropShadow?.distance ?? 0) - (a._stroke?.width ?? 0);
if (this.chars[g] = {
id: g.codePointAt(0),
xOffset: -this._padding,
yOffset: -this._padding,
xAdvance: A,
kerning: {}
}, f) {
this._drawGlyph(
i,
_,
l + h,
u + h,
d,
a
);
const k = n.width * d, ue = n.height * d, st = new at(
l / k * n.width,
u / ue * n.height,
M / k * n.width,
G / ue * n.height
);
this.chars[g].texture = new w({
source: n,
frame: st
}), l += Math.ceil(M);
}
}
n.update(), this._currentX = l, this._currentY = u, this._currentMaxCharHeight = c, this._skipKerning && this._applyKerning(t, i);
}
/**
* @deprecated since 8.0.0
* The map of base page textures (i.e., sheets of glyphs).
*/
get pageTextures() {
return T(B, "BitmapFont.pageTextures is deprecated, please use BitmapFont.pages instead."), this.pages;
}
_applyKerning(e, t) {
const r = this._measureCache;
for (let s = 0; s < e.length; s++) {
const i = e[s];
for (let n = 0; n < this._currentChars.length; n++) {
const a = this._currentChars[n];
let l = r[i];
l || (l = r[i] = t.measureText(i).width);
let u = r[a];
u || (u = r[a] = t.measureText(a).width);
let c = t.measureText(i + a).width, d = c - (l + u);
d && (this.chars[i].kerning[a] = d), c = t.measureText(i + a).width, d = c - (l + u), d && (this.chars[a].kerning[i] = d);
}
}
}
_nextPage() {
this._currentPageIndex++;
const e = this.resolution, t = V.getOptimalCanvasAndContext(
this._textureSize,
this._textureSize,
e
);
this._setupContext(t.context, this._style, e);
const r = e * (this.baseRenderedFontSize / this.baseMeasurementFontSize), s = new w({
source: new ot({
resource: t.canvas,
resolution: r,
alphaMode: "premultiply-alpha-on-upload",
autoGenerateMipmaps: this._mipmap
})
});
this._textureStyle && (s.source.style = this._textureStyle);
const i = {
canvasAndContext: t,
texture: s
};
return this.pages[this._currentPageIndex] = i, i;
}
// canvas style!
_setupContext(e, t, r) {
t.fontSize = this.baseRenderedFontSize, e.scale(r, r), e.font = ce(t), t.fontSize = this.baseMeasurementFontSize, e.textBaseline = t.textBaseline;
const s = t._stroke, i = s?.width ?? 0;
if (s && (e.lineWidth = i, e.lineJoin = s.join, e.miterLimit = s.miterLimit, e.strokeStyle = he(s, e)), t._fill && (e.fillStyle = he(t._fill, e)), t.dropShadow) {
const n = t.dropShadow, a = Te.shared.setValue(n.color).toArray(), l = n.blur * r, u = n.distance * r;
e.shadowColor = `rgba(${a[0] * 255},${a[1] * 255},${a[2] * 255},${n.alpha})`, e.shadowBlur = l, e.shadowOffsetX = Math.cos(n.angle) * u, e.shadowOffsetY = Math.sin(n.angle) * u;
} else
e.shadowColor = "black", e.shadowBlur = 0, e.shadowOffsetX = 0, e.shadowOffsetY = 0;
}
_drawGlyph(e, t, r, s, i, n) {
const a = t.text, l = t.fontProperties, c = (n._stroke?.width ?? 0) * i, d = r + c / 2, h = s - c / 2, f = l.descent * i, b = t.lineHeight * i;
let x = !1;
n.stroke && c && (x = !0, e.strokeText(a, d, h + b - f));
const { shadowBlur: p, shadowOffsetX: g, shadowOffsetY: _ } = e;
n._fill && (x && (e.shadowBlur = 0, e.shadowOffsetX = 0, e.shadowOffsetY = 0), e.fillText(a, d, h + b - f)), x && (e.shadowBlur = p, e.shadowOffsetX = g, e.shadowOffsetY = _);
}
destroy() {
super.destroy();
for (let e = 0; e < this.pages.length; e++) {
const { canvasAndContext: t, texture: r } = this.pages[e];
V.returnCanvasAndContext(t), r.destroy(!0);
}
this.pages = null;
}
};
Ge.defaultOptions = {
textureSize: 512,
style: new I(),
mipmap: !0
};
let fe = Ge;
function ke(o, e, t, r) {
const s = {
width: 0,
height: 0,
offsetY: 0,
scale: e.fontSize / t.baseMeasurementFontSize,
lines: [{
width: 0,
charPositions: [],
spaceWidth: 0,
spacesIndex: [],
chars: []
}]
};
s.offsetY = t.baseLineOffset;
let i = s.lines[0], n = null, a = !0;
const l = {
width: 0,
start: 0,
index: 0,
// use index to not modify the array as we use it a lot!
positions: [],
chars: []
}, u = t.baseMeasurementFontSize / e.fontSize, c = e.letterSpacing * u, d = e.wordWrapWidth * u, h = e.lineHeight ? e.lineHeight * u : t.lineHeight, f = e.wordWrap && e.breakWords, b = (g) => {
const _ = i.width;
for (let y = 0; y < l.index; y++) {
const S = g.positions[y];
i.chars.push(g.chars[y]), i.charPositions.push(S + _);
}
i.width += g.width, a = !1, l.width = 0, l.index = 0, l.chars.length = 0;
}, x = () => {
let g = i.chars.length - 1;
if (r) {
let _ = i.chars[g];
for (; _ === " "; )
i.width -= t.chars[_].xAdvance, _ = i.chars[--g];
}
s.width = Math.max(s.width, i.width), i = {
width: 0,
charPositions: [],
chars: [],
spaceWidth: 0,
spacesIndex: []
}, a = !0, s.lines.push(i), s.height += h;
}, p = (g) => g - c > d;
for (let g = 0; g < o.length + 1; g++) {
let _;
const y = g === o.length;
y || (_ = o[g]);
const S = t.chars[_] || t.chars[" "];
if (/(?:\s)/.test(_) || _ === "\r" || _ === `
` || y) {
if (!a && e.wordWrap && p(i.width + l.width) ? (x(), b(l), y || i.charPositions.push(0)) : (l.start = i.width, b(l), y || i.charPositions.push(0)), _ === "\r" || _ === `
`)
i.width !== 0 && x();
else if (!y) {
const A = S.xAdvance + (S.kerning[n] || 0) + c;
i.width += A, i.spaceWidth = A, i.spacesIndex.push(i.charPositions.length), i.chars.push(_);
}
} else {
const G = S.kerning[n] || 0, A = S.xAdvance + G + c;
f && p(i.width + l.width + A) && (b(l), x()), l.positions[l.index++] = l.width + G, l.chars.push(_), l.width += A;
}
n = _;
}
return x(), e.align === "center" ? Tt(s) : e.align === "right" ? wt(s) : e.align === "justify" && St(s), s;
}
function Tt(o) {
for (let e = 0; e < o.lines.length; e++) {
const t = o.lines[e], r = o.width / 2 - t.width / 2;
for (let s = 0; s < t.charPositions.length; s++)
t.charPositions[s] += r;
}
}
function wt(o) {
for (let e = 0; e < o.lines.length; e++) {
const t = o.lines[e], r = o.width - t.width;
for (let s = 0; s < t.charPositions.length; s++)
t.charPositions[s] += r;
}
}
function St(o) {
const e = o.width;
for (let t = 0; t < o.lines.length; t++) {
const r = o.lines[t];
let s = 0, i = r.spacesIndex[s++], n = 0;
const a = r.spacesIndex.length, u = (e - r.width) / a;
for (let c = 0; c < r.charPositions.length; c++)
c === i && (i = r.spacesIndex[s++], n += u), r.charPositions[c] += n;
}
}
function Pt(o) {
if (o === "")
return [];
typeof o == "string" && (o = [o]);
const e = [];
for (let t = 0, r = o.length; t < r; t++) {
const s = o[t];
if (Array.isArray(s)) {
if (s.length !== 2)
throw new Error(`[BitmapFont]: Invalid character range length, expecting 2 got ${s.length}.`);
if (s[0].length === 0 || s[1].length === 0)
throw new Error("[BitmapFont]: Invalid character delimiter.");
const i = s[0].charCodeAt(0), n = s[1].charCodeAt(0);
if (n < i)
throw new Error("[BitmapFont]: Invalid character range.");
for (let a = i, l = n; a <= l; a++)
e.push(String.fromCharCode(a));
} else
e.push(...Array.from(s));
}
if (e.length === 0)
throw new Error("[BitmapFont]: Empty set when resolving characters.");
return e;
}
let L = 0;
class Ct {
constructor() {
this.ALPHA = [["a", "z"], ["A", "Z"], " "], this.NUMERIC = [["0", "9"]], this.ALPHANUMERIC = [["a", "z"], ["A", "Z"], ["0", "9"], " "], this.ASCII = [[" ", "~"]], this.defaultOptions = {
chars: this.ALPHANUMERIC,
resolution: 1,
padding: 4,
skipKerning: !1,
textureStyle: null
};
}
/**
* 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(e, t) {
let r = `${t.fontFamily}-bitmap`, s = !0;
if (t._fill.fill && !t._stroke)
r += t._fill.fill.styleKey, s = !1;
else if (t._stroke || t.dropShadow) {
let n = t.styleKey;
n = n.substring(0, n.lastIndexOf("-")), r = `${n}-bitmap`, s = !1;
}
if (!P.has(r)) {
const n = Object.create(t);
n.lineHeight = 0;
const a = new fe({
style: n,
overrideFill: s,
overrideSize: !0,
...this.defaultOptions
});
L++, L > 50 && te("BitmapText", `You have dynamically created ${L} bitmap fonts, this can be inefficient. Try pre installing your font styles using \`BitmapFont.install({name:"style1", style})\``), a.once("destroy", () => {
L--, P.remove(r);
}), P.set(
r,
a
);
}
const i = P.get(r);
return i.ensureCharacters?.(e), i;
}
/**
* 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(e, t, r = !0) {
const s = this.getFont(e, t), i = D.graphemeSegmenter(e);
return ke(i, t, s, r);
}
/**
* 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(e, t, r = !0) {
return this.getLayout(e, t, r);
}
// eslint-disable-next-line max-len
install(...e) {
let t = e[0];
typeof t == "string" && (t = {
name: t,
style: e[1],
chars: e[2]?.chars,
resolution: e[2]?.resolution,
padding: e[2]?.padding,
skipKerning: e[2]?.skipKerning
}, T(B, "BitmapFontManager.install(name, style, options) is deprecated, use BitmapFontManager.install({name, style, ...options})"));
const r = t?.name;
if (!r)
throw new Error("[BitmapFontManager] Property `name` is required.");
t = { ...this.defaultOptions, ...t };
const s = t.style, i = s instanceof I ? s : new I(s), n = t.dynamicFill ?? this._canUseTintForStyle(i), a = new fe({
style: i,
overrideFill: n,
skipKerning: t.skipKerning,
padding: t.padding,
resolution: t.resolution,
overrideSize: !1,
textureStyle: t.textureStyle
}), l = Pt(t.chars);
return a.ensureCharacters(l.join("")), P.set(`${r}-bitmap`, a), a.once("destroy", () => P.remove(`${r}-bitmap`)), a;
}
/**
* Uninstalls a bitmap font from the cache.
* @param {string} name - The name of the bitmap font to uninstall.
*/
uninstall(e) {
const t = `${e}-bitmap`, r = P.get(t);
r && r.destroy();
}
/**
* Determines if a style can use tinting instead of baking colors into the bitmap.
* Tinting is more efficient as it allows reusing the same bitmap with different colors.
* @param style - The text style to evaluate
* @returns true if the style can use tinting, false if colors must be baked in
* @private
*/
_canUseTintForStyle(e) {
return !e._stroke && (!e.dropShadow || e.dropShadow.color === 0) && !e._fill.fill && e._fill.color === 16777215;
}
}
const Ft = new Ct();
class ze {
constructor(e) {
this._renderer = e;
}
push(e, t, r) {
this._renderer.renderPipes.batch.break(r), r.add({
renderPipeId: "filter",
canBundle: !1,
action: "pushFilter",
container: t,
filterEffect: e
});
}
pop(e, t, r) {
this._renderer.renderPipes.batch.break(r), r.add({
renderPipeId: "filter",
action: "popFilter",
canBundle: !1
});
}
execute(e) {
e.action === "pushFilter" ? this._renderer.filter.push(e) : e.action === "popFilter" && this._renderer.filter.pop();
}
destroy() {
this._renderer = null;
}
}
ze.extension = {
type: [
m.WebGLPipes,
m.WebGPUPipes,
m.CanvasPipes
],
name: "filter"
};
function Bt(o, e) {
e.clear();
const t = e.matrix;
for (let r = 0; r < o.length; r++) {
const s = o[r];
s.globalDisplayStatus < 7 || (e.matrix = s.worldTransform, e.addBounds(s.bounds));
}
return e.matrix = t, e;
}
const Ut = new re({
attributes: {
aPosition: {
buffer: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]),
format: "float32x2",
stride: 8,
offset: 0
}
},
indexBuffer: new Uint32Array([0, 1, 2, 0, 2, 3])
});
class Mt {
constructor() {
this.skip = !1, this.inputTexture = null, this.backTexture = null, this.filters = null, this.bounds = new Se(), this.container = null, this.blendRequired = !1, this.outputRenderSurface = null, this.globalFrame = { x: 0, y: 0, width: 0, height: 0 };
}
}
class De {
constructor(e) {
this._filterStackIndex = 0, this._filterStack = [], this._filterGlobalUniforms = new z({
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 we({}), this.renderer = e;
}
/**
* The back texture of the currently active filter. Requires the filter to have `blendRequired` set to true.
* @readonly
*/
get activeBackTexture() {
return this._activeFilterData?.backTexture;
}
/**
* Pushes a filter instruction onto the filter stack.
* @param instruction - The instruction containing the filter effect and container.
* @internal
*/
push(e) {
const t = this.renderer, r = e.filterEffect.filters, s = this._pushFilterData();
s.skip = !1, s.filters = r, s.container = e.container, s.outputRenderSurface = t.renderTarget.renderSurface;
const i = t.renderTarget.renderTarget.colorTexture.source, n = i.resolution, a = i.antialias;
if (r.length === 0) {
s.skip = !0;
return;
}
const l = s.bounds;
if (this._calculateFilterArea(e, l), this._calculateFilterBounds(s, t.renderTarget.rootViewPort, a, n, 1), s.skip)
return;
const u = this._getPreviousFilterData(), c = this._findFilterResolution(n);
let d = 0, h = 0;
u && (d = u.bounds.minX, h = u.bounds.minY), this._calculateGlobalFrame(
s,
d,
h,
c,
i.width,
i.height
), this._setupFilterTextures(s, l, t, u);
}
/**
* Applies filters to a texture.
*
* This method takes a texture and a list of filters, applies the filters to the texture,
* and returns the resulting texture.
* @param {object} params - The parameters for applying filters.
* @param {Texture} params.texture - The texture to apply filters to.
* @param {Filter[]} params.filters - The filters to apply.
* @returns {Texture} The resulting texture after all filters have been applied.
* @example
*
* ```ts
* // Create a texture and a list of filters
* const texture = new Texture(...);
* const filters = [new BlurFilter(), new ColorMatrixFilter()];
*
* // Apply the filters to the texture
* const resultTexture = filterSystem.applyToTexture({ texture, filters });
*
* // Use the resulting texture
* sprite.texture = resultTexture;
* ```
*
* Key Points:
* 1. padding is not currently supported here - so clipping may occur with filters that use padding.
* 2. If all filters are disabled or skipped, the original texture is returned.
*/
generateFilteredTexture({ texture: e, filters: t }) {
const r = this._pushFilterData();
this._activeFilterData = r, r.skip = !1, r.filters = t;
const s = e.source, i = s.resolution, n = s.antialias;
if (t.length === 0)
return r.skip = !0, e;
const a = r.bounds;
if (a.addRect(e.frame), this._calculateFilterBounds(r, a.rectangle, n, i, 0), r.skip)
return e;
const l = i;
this._calculateGlobalFrame(
r,
0,
0,
l,
s.width,
s.height
), r.outputRenderSurface = C.getOptimalTexture(
a.width,
a.height,
r.resolution,
r.antialias
), r.backTexture = w.EMPTY, r.inputTexture = e, this.renderer.renderTarget.finishRenderPass(), this._applyFiltersToTexture(r, !0);
const h = r.outputRenderSurface;
return h.source.alphaMode = "premultiplied-alpha", h;
}
/** @internal */
pop() {
const e = this.renderer, t = this._popFilterData();
t.skip || (e.globalUniforms.pop(), e.renderTarget.finishRenderPass(), this._activeFilterData = t, this._applyFiltersToTexture(t, !1), t.blendRequired && C.returnTexture(t.backTexture), C.returnTexture(t.inputTexture));
}
/**
* Copies the last render surface to a texture.
* @param lastRenderSurface - The last render surface to copy from.
* @param bounds - The bounds of the area to copy.
* @param previousBounds - The previous bounds to use for offsetting the copy.
*/
getBackTexture(e, t, r) {
const s = e.colorTexture.source._resolution, i = C.getOptimalTexture(
t.width,
t.height,
s,
!1
);
let n = t.minX, a = t.minY;
r && (n -= r.minX, a -= r.minY), n = Math.floor(n * s), a = Math.floor(a * s);
const l = Math.ceil(t.width * s), u = Math.ceil(t.height * s);
return this.renderer.renderTarget.copyToTexture(
e,
i,
{ x: n, y: a },
{ width: l, height: u },
{ x: 0, y: 0 }
), i;
}
/**
* Applies a filter to a texture.
* @param filter - The filter to apply.
* @param input - The input texture.
* @param output - The output render surface.
* @param clear - Whether to clear the output surface before applying the filter.
*/
applyFilter(e, t, r, s) {
const i = this.renderer, n = this._activeFilterData, l = n.outputRenderSurface === r, u = i.renderTarget.rootRenderTarget.colorTexture.source._resolution, c = this._findFilterResolution(u);
let d = 0, h = 0;
if (l) {
const f = this._findPreviousFilterOffset();
d = f.x, h = f.y;
}
this._updateFilterUniforms(t, r, n, d, h, c, l, s), this._setupBindGroupsAndRender(e, t, i);
}
/**
* 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(e, t) {
const r = this._activeFilterData, s = e.set(
r.inputTexture._source.width,
0,
0,
r.inputTexture._source.height,
r.bounds.minX,
r.bounds.minY
), i = t.worldTransform.copyTo(U.shared), n = t.renderGroup || t.parentRenderGroup;
return n && n.cacheToLocalTransform && i.prepend(n.cacheToLocalTransform), i.invert(), s.prepend(i), s.scale(
1 / t.texture.orig.width,
1 / t.texture.orig.height
), s.translate(t.anchor.x, t.anchor.y), s;
}
destroy() {
}
/**
* Sets up the bind groups and renders the filter.
* @param filter - The filter to apply
* @param input - The input texture
* @param renderer - The renderer instance
*/
_setupBindGroupsAndRender(e, t, r) {
if (r.renderPipes.uniformBatch) {
const s = r.renderPipes.uniformBatch.getUboResource(this._filterGlobalUniforms);
this._globalFilterBindGroup.setResource(s, 0);
} else
this._globalFilterBindGroup.setResource(this._filterGlobalUniforms, 0);
this._globalFilterBindGroup.setResource(t.source, 1), this._globalFilterBindGroup.setResource(t.source.style, 2), e.groups[0] = this._globalFilterBindGroup, r.encoder.draw({
geometry: Ut,
shader: e,
state: e._state,
topology: "triangle-list"
}), r.type === se.WEBGL && r.renderTarget.finishRenderPass();
}
/**
* Sets up the filter textures including input texture and back texture if needed.
* @param filterData - The filter data to update
* @param bounds - The bounds for the texture
* @param renderer - The renderer instance
* @param previousFilterData - The previous filter data for back texture calculation
*/
_setupFilterTextures(e, t, r, s) {
if (e.backTexture = w.EMPTY, e.blendRequired) {
r.renderTarget.finishRenderPass();
const i = r.renderTarget.getRenderTarget(e.outputRenderSurface);
e.backTexture = this.getBackTexture(i, t, s?.bounds);
}
e.inputTexture = C.getOptimalTexture(
t.width,
t.height,
e.resolution,
e.antialias
), r.renderTarget.bind(e.inputTexture, !0), r.globalUniforms.push({
offset: t
});
}
/**
* Calculates and sets the global frame for the filter.
* @param filterData - The filter data to update
* @param offsetX - The X offset
* @param offsetY - The Y offset
* @param globalResolution - The global resolution
* @param sourceWidth - The source texture width
* @param sourceHeight - The source texture height
*/
_calculateGlobalFrame(e, t, r, s, i, n) {
const a = e.globalFrame;
a.x = t * s, a.y = r * s, a.width = i * s, a.height = n * s;
}
/**
* Updates the filter uniforms with the current filter state.
* @param input - The input texture
* @param output - The output render surface
* @param filterData - The current filter data
* @param offsetX - The X offset for positioning
* @param offsetY - The Y offset for positioning
* @param resolution - The current resolution
* @param isFinalTarget - Whether this is the final render target
* @param clear - Whether to clear the output surface
*/
_updateFilterUniforms(e, t, r, s, i, n, a, l) {
const u = this._filterGlobalUniforms.uniforms, c = u.uOutputFrame, d = u.uInputSize, h = u.uInputPixel, f = u.uInputClamp, b = u.uGlobalFrame, x = u.uOutputTexture;
a ? (c[0] = r.bounds.minX - s, c[1] = r.bounds.minY - i) : (c[0] = 0, c[1] = 0), c[2] = e.frame.width, c[3] = e.frame.height, d[0] = e.source.width, d[1] = e.source.height, d[2] = 1 / d[0], d[3] = 1 / d[1], h[0] = e.source.pixelWidth, h[1] = e.source.pixelHeight, h[2] = 1 / h[0], h[3] = 1 / h[1], f[0] = 0.5 * h[2], f[1] = 0.5 * h[3], f[2] = e.frame.width * d[2] - 0.5 * h[2], f[3] = e.frame.height * d[3] - 0.5 * h[3];
const p = this.renderer.renderTarget.rootRenderTarget.colorTexture;
b[0] = s * n, b[1] = i * n, b[2] = p.source.width * n, b[3] = p.source.height * n, t instanceof w && (t.source.resource = null);
const g = this.renderer.renderTarget.getRenderTarget(t);
this.renderer.renderTarget.bind(t, !!l), t instanceof w ? (x[0] = t.frame.width, x[1] = t.frame.height) : (x[0] = g.width, x[1] = g.height), x[2] = g.isRoot ? -1 : 1, this._filterGlobalUniforms.update();
}
/**
* Finds the correct resolution by looking back through the filter stack.
* @param rootResolution - The fallback root resolution to use
* @returns The resolution from the previous filter or root resolution
*/
_findFilterResolution(e) {
let t = this._filterStackIndex - 1;
for (; t > 0 && this._filterStack[t].skip; )
--t;
return t > 0 && this._filterStack[t].inputTexture ? this._filterStack[t].inputTexture.source._resolution : e;
}
/**
* Finds the offset from the previous non-skipped filter in the stack.
* @returns The offset coordinates from the previous filter
*/
_findPreviousFilterOffset() {
let e = 0, t = 0, r = this._filterStackIndex;
for (; r > 0; ) {
r--;
const s = this._filterStack[r];
if (!s.skip) {
e = s.bounds.minX, t = s.bounds.minY;
break;
}
}
return { x: e, y: t };
}
/**
* Calculates the filter area bounds based on the instruction type.
* @param instruction - The filter instruction
* @param bounds - The bounds object to populate
*/
_calculateFilterArea(e, t) {
if (e.renderables ? Bt(e.renderables, t) : e.filterEffect.filterArea ? (t.clear(), t.addRect(e.filterEffect.filterArea), t.applyMatrix(e.container.worldTransform)) : e.container.getFastGlobalBounds(!0, t), e.container) {
const s = (e.container.renderGroup || e.container.parentRenderGroup).cacheToLocalTransform;
s && t.applyMatrix(s);
}
}
_applyFiltersToTexture(e, t) {
const r = e.inputTexture, s = e.bounds, i = e.filters;
if (this._globalFilterBindGroup.setResource(r.source.style, 2), this._globalFilterBindGroup.setResource(e.backTexture.source, 3), i.length === 1)
i[0].apply(this, r, e.outputRenderSurface, t);
else {
let n = e.inputTexture;
const a = C.getOptimalTexture(
s.width,
s.height,
n.source._resolution,
!1
);
let l = a, u = 0;
for (u = 0; u < i.length - 1; ++u) {
i[u].apply(this, n, l, !0);
const d = n;
n = l, l = d;
}
i[u].apply(this, n, e.outputRenderSurface, t), C.returnTexture(a);
}
}
_calculateFilterBounds(e, t, r, s, i) {
const n = this.renderer, a = e.bounds, l = e.filters;
let u = 1 / 0, c = 0, d = !0, h = !1, f = !1, b = !0;
for (let x = 0; x < l.length; x++) {
const p = l[x];
if (u = Math.min(u, p.resolution === "inherit" ? s : p.resolution), c += p.padding, p.antialias === "off" ? d = !1 : p.antialias === "inherit" && d && (d = r), p.clipToViewport || (b = !1), !!!(p.compatibleRenderers & n.type)) {
f = !1;
break;
}
if (p.blendRequired && !(n.backBuffer?.useBackBuffer ?? !0)) {
te("Blend filter requires backBuffer on WebGL renderer to be enabled. Set `useBackBuffer: true` in the renderer options."), f = !1;
break;
}
f = p.enabled || f, h || (h = p.blendRequired);
}
if (!f) {
e.skip = !0;
return;
}
if (b && a.fitBounds(0, t.width / s, 0, t.height / s), a.scale(u).ceil().scale(1 / u).pad((c | 0) * i), !a.isPositive) {
e.skip = !0;
return;
}
e.antialias = d, e.resolution = u, e.blendRequired = h;
}
_popFilterData() {
return this._filterStackIndex--, this._filterStack[this._filterStackIndex];
}
_getPreviousFilterData() {
let e, t = this._filterStackIndex - 1;
for (; t > 1 && (t--, e = this._filterStack[t], !!e.skip); )
;
return e;
}
_pushFilterData() {
let e = this._filterStack[this._filterStackIndex];
return e || (e = this._filterStack[this._filterStackIndex] = new Mt()), this._filterStackIndex++, e;
}
}
De.extension = {
type: [
m.WebGLSystem,
m.WebGPUSystem
],
name: "filter"
};
const Oe = class We extends re {
constructor(...e) {
let t = e[0] ?? {};
t instanceof Float32Array && (T(B, "use new MeshGeometry({ positions, uvs, indices }) instead"), t = {
positions: t,
uvs: e[1],
indices: e[2]
}), t = { ...We.defaultOptions, ...t };
const r = t.positions || new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
let s = t.uvs;
s || (t.positions ? s = new Float32Array(r.length) : s = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]));
const i = t.indices || new Uint32Array([0, 1, 2, 0, 2, 3]), n = t.shrinkBuffersToFit, a = new O({
data: r,
label: "attribute-mesh-positions",
shrinkToFit: n,
usage: F.VERTEX | F.COPY_DST
}), l = new O({
data: s,
label: "attribute-mesh-uvs",
shrinkToFit: n,
usage: F.VERTEX | F.COPY_DST
}), u = new O({
data: i,
label: "index-mesh-buffer",
shrinkToFit: n,
usage: F.INDEX | F.COPY_DST
});
super({
attributes: {
aPosition: {
buffer: a,
format: "float32x2",
stride: 8,
offset: 0
},
aUV: {
buffer: l,
format: "float32x2",
stride: 8,
offset: 0
}
},
indexBuffer: u,
topology: t.topology
}), this.batchMode = "auto";
}
/** The positions of the mesh. */
get positions() {
return this.attributes.aPosition.buffer.data;
}
/**
* Set the positions of the mesh.
* When setting the positions, its important that the uvs array is at least as long as the positions array.
* otherwise the geometry will not be valid.
* @param {Float32Array} value - The positions of the mesh.
*/
set positions(e) {
this.attributes.aPosition.buffer.data = e;
}
/** The UVs of the mesh. */
get uvs() {
return this.attributes.aUV.buffer.data;
}
/**
* Set the UVs of the mesh.
* Its important that the uvs array you set is at least as long as the positions array.
* otherwise the geometry will not be valid.
* @param {Float32Array} value - The UVs of the mesh.
*/
set uvs(e) {
this.attributes.aUV.buffer.data = e;
}
/** The indices of the mesh. */
get indices() {
return this.indexBuffer.data;
}
set indices(e) {
this.indexBuffer.data = e;
}
};
Oe.defaultOptions = {
topology: "triangle-list",
shrinkBuffersToFit: !1
};
let oe = Oe;
const pe = "http://www.w3.org/2000/svg", ge = "http://www.w3.org/1999/xhtml";
class Ie {
constructor() {
this.svgRoot = document.createElementNS(pe, "svg"), this.foreignObject = document.createElementNS(pe, "foreignObject"), this.domElement = document.createElementNS(ge, "div"), this.styleElement = document.createElementNS(ge, "style");
const { foreignObject: e, svgRoot: t, styleElement: r, domElement: s } = this;
e.setAttribute("width", "10000"), e.setAttribute("height", "10000"), e.style.overflow = "hidden", t.appendChild(e), e.appendChild(r), e.appendChild(s), this.image = ie.get().createImage();
}
}
let me;
function Rt(o, e, t, r) {
r || (r = me || (me = new Ie()));
const { domElement: s, styleElement: i, svgRoot: n } = r;
s.innerHTML = `<style>${e.cssStyle};</style><div style='padding:0'>${o}</div>`, s.setAttribute("style", "transform-origin: top left; display: inline-block"), t && (i.textContent = t), document.body.appendChild(n);
const a = s.getBoundingClientRect();
n.remove();
const l = e.padding * 2;
return {
width: a.width - l,
height: a.height - l
};
}
class Gt {
constructor() {
this.batches = [], this.batched = !1;
}
destroy() {
this.batches.forEach((e) => {
Y.return(e);
}), this.batches.length = 0;
}
}
class Ee {
constructor(e, t) {
this.state = X.for2d(), this.renderer = e, this._adaptor = t, this.renderer.runners.contextChange.add(this);
}
contextChange() {
this._adaptor.contextChange(this.renderer);
}
validateRenderable(e) {
const t = e.context, r = !!e._gpuData, s = this.renderer.graphicsContext.updateGpuContext(t);
return !!(s.isBatchable || r !== s.isBatchable);
}
addRenderable(e, t) {
const r = this.renderer.graphicsContext.updateGpuContext(e.context);
e.didViewUpdate && this._rebuild(e), r.isBatchable ? this._addToBatcher(e, t) : (this.renderer.renderPipes.batch.break(t), t.add(e));
}
updateRenderable(e) {
const r = this._getGpuDataForRenderable(e).batches;
for (let s = 0; s < r.length; s++) {
const i = r[s];
i._batcher.updateElement(i);
}
}
execute(e) {
if (!e.isRenderable)
return;
const t = this.renderer, r = e.context;
if (!t.graphicsContext.getGpuContext(r).batches.length)
return;
const i = r.customShader || this._adaptor.shader;
this.state.blendMode = e.groupBlendMode;
const n = i.resources.localUniforms.uniforms;
n.uTransformMatrix = e.groupTransform, n.uRound = t._roundPixels | e._roundPixels, j(
e.groupColorAlpha,
n.uColor,
0
), this._adaptor.execute(this, e);
}
_rebuild(e) {
const t = this._getGpuDataForRenderable(e), r = this.renderer.graphicsContext.updateGpuContext(e.context);
t.destroy(), r.isBatchable && this._updateBatchesForRenderable(e, t);
}
_addToBatcher(e, t) {
const r = this.renderer.renderPipes.batch, s = this._getGpuDataForRenderable(e).batches;
for (let i = 0; i < s.length; i++) {
const n = s[i];
r.addToBatch(n, t);
}
}
_getGpuDataForRenderable(e) {
return e._gpuData[this.renderer.uid] || this._initGpuDataForRenderable(e);
}
_initGpuDataForRenderable(e) {
const t = new Gt();
return e._gpuData[this.renderer.uid] = t, t;
}
_updateBatchesForRenderable(e, t) {
const r = e.context, s = this.renderer.graphicsContext.getGpuContext(r), i = this.renderer._roundPixels | e._roundPixels;
t.batches = s.batches.map((n) => {
const a = Y.get(lt);
return n.copyTo(a), a.renderable = e, a.roundPixels = i, a;
});
}
destroy() {
this.renderer = null, this._adaptor.destroy(), this._adaptor = null, this.state = null;
}
}
Ee.extension = {
type: [
m.WebGLPipes,
m.WebGPUPipes,
m.CanvasPipes
],
name: "graphics"
};
const Le = class He extends oe {
constructor(...e) {
super({});
let t = e[0] ?? {};
typeof t == "number" && (T(B, "PlaneGeometry constructor changed please use { width, height, verticesX, verticesY } instead"), t = {
width: t,
height: e[1],
verticesX: e[2],
verticesY: e[3]
}), this.build(t);
}
/**
* Refreshes plane coordinates
* @param options - Options to be applied to plane geometry
*/
build(e) {
e = { ...He.defaultOptions, ...e }, this.verticesX = this.verticesX ?? e.verticesX, this.verticesY = this.verticesY ?? e.verticesY, this.width = this.width ?? e.width, this.height = this.height ?? e.height;
const t = this.verticesX * this.verticesY, r = [], s = [], i = [], n = this.verticesX - 1, a = this.verticesY - 1, l = this.width / n, u = this.height / a;
for (let d = 0; d < t; d++) {
const h = d % this.verticesX, f = d / this.verticesX | 0;
r.push(h * l, f * u), s.push(h / n, f / a);
}
const c = n * a;
for (let d = 0; d < c; d++) {
const h = d % n, f = d / n | 0, b = f * this.verticesX + h, x = f * this.verticesX + h + 1, p = (f + 1) * this.verticesX + h, g = (f + 1) * this.verticesX + h + 1;
i.push(
b,
x,
p,
x,
g,
p
);
}
this.buffers[0].data = new Float32Array(r), this.buffers[1].data = new Float32Array(s), this.indexBuffer.data = new Uint32Array(i), this.buffers[0].update(), this.buffers[1].update(), this.indexBuffer.update();
}
};
Le.defaultOptions = {
width: 100,
height: 100,
verticesX: 10,
verticesY: 10
};
let At = Le;
class le {
constructor() {
this.batcherName = "default", this.packAsQuad = !1, this.indexOffset = 0, this.attributeOffset = 0, this.roundPixels = 0, this._batcher = null, this._batch = null, this._textureMatrixUpdateId = -1, this._uvUpdateId = -1;
}
get blendMode() {
return this.renderable.groupBlendMode;
}
get topology() {
return this._topology || this.geometry.topology;
}
set topology(e) {
this._topology = e;
}
reset() {
this.renderable = null, this.texture = null, this._batcher = null, this._batch = null, this.geometry = null, this._uvUpdateId = -1, this._textureMatrixUpdateId = -1;
}
/**
* Sets the texture for the batchable mesh.
* As it does so, it resets the texture matrix update ID.
* this is to ensure that the texture matrix is recalculated when the uvs are referenced
* @param value - The texture to set.
*/
setTexture(e) {
this.texture !== e && (this.texture = e, this._textureMatrixUpdateId = -1);
}
get uvs() {
const t = this.geometry.getBuffer("aUV"), r = t.data;
let s = r;
const i = this.texture.textureMatrix;
return i.isSimple || (s = this._transformedUvs, (this._textureMatrixUpdateId !== i._updateID || this._uvUpdateId !== t._updateID) && ((!s || s.length < r.length) && (s = this._transformedUvs = new Float32Array(r.length)), this._textureMatrixUpdateId = i._updateID, this._uvUpdateId = t._updateID, i.multiplyUvs(r, s))), s;
}
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;
}
}
class xe {
destroy() {
}
}
class Ve {
constructor(e, t) {
this.localUniforms = new z({
uTransformMatrix: { value: new U(), type: "mat3x3<f32>" },
uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
uRound: { value: 0, type: "f32" }
}), this.localUniformsBindGroup = new we({
0: this.localUniforms
}), this.renderer = e, this._adaptor = t, this._adaptor.init();
}
validateRenderable(e) {
const t = this._getMeshData(e), r = t.batched, s = e.batched;
if (t.batched = s, r !== s)
return !0;
if (s) {
const i = e._geometry;
if (i.indices.length !== t.indexSize || i.positions.length !== t.vertexSize)
return t.indexSize = i.indices.length, t.vertexSize = i.positions.length, !0;
const n = this._getBatchableMesh(e);
return n.texture.uid !== e._texture.uid && (n._textureMatrixUpdateId = -1), !n._batcher.checkAndUpdateTexture(
n,
e._texture
);
}
return !1;
}
addRenderable(e, t) {
const r = this.renderer.renderPipes.batch, s = this._getMeshData(e);
if (e.didViewUpdate && (s.indexSize = e._geometry.indices?.length, s.vertexSize = e._geometry.positions?.length), s.batched) {
const i = this._getBatchableMesh(e);
i.setTexture(e._texture), i.geometry = e._geometry, r.addToBatch(i, t);
} else
r.break(t), t.add(e);
}
updateRenderable(e) {
if (e.batched) {
const t = this._getBatchableMesh(e);
t.setTexture(e._texture), t.geometry = e._geometry, t._batcher.updateElement(t);
}
}
execute(e) {
if (!e.isRenderable)
return;
e.state.blendMode = ne(e.groupBlendMode, e.texture._source);
const t = this.localUniforms;
t.uniforms.uTransformMatrix = e.groupTransform, t.uniforms.uRound = this.renderer._roundPixels | e._roundPixels, t.update(), j(
e.groupColorAlpha,
t.uniforms.uColor,
0
), this._adaptor.execute(this, e);
}
_getMeshData(e) {
var t, r;
return (t = e._gpuData)[r = this.renderer.uid] || (t[r] = new xe()), e._gpuData[this.renderer.uid].meshData || this._initMeshData(e);
}
_initMeshData(e) {
return e._gpuData[this.renderer.uid].meshData = {
batched: e.batched,
indexSize: 0,
vertexSize: 0
}, e._gpuData[this.renderer.uid].meshData;
}
_getBatchableMesh(e) {
var t, r;
return (t = e._gpuData)[r = this.renderer.uid] || (t[r] = new xe()), e._gpuData[this.renderer.uid].batchableMesh || this._initBatchableMesh(e);
}
_initBatchableMesh(e) {
const t = new le();
return t.renderable = e, t.setTexture(e._texture), t.transform = e.groupTransform, t.roundPixels = this.renderer._roundPixels | e._roundPixels, e._gpuData[this.renderer.uid].batchableMesh = t, t;
}
destroy() {
this.localUniforms = null, this.localUniformsBindGroup = null, this._adaptor.destroy(), this._adaptor = null, this.renderer = null;
}
}
Ve.extension = {
type: [
m.WebGLPipes,
m.WebGPUPipes,
m.CanvasPipes
],
name: "mesh"
};
class kt {
execute(e, t) {
const r = e.state, s = e.renderer, i = t.shader || e.defaultShader;
i.resources.uTexture = t.texture._source, i.resources.uniforms = e.localUniforms;
const n = s.gl, a = e.getBuffers(t);
s.shader.bind(i), s.state.set(r), s.geometry.bind(a.geometry, i.glProgram);
const u = a.geometry.indexBuffer.data.BYTES_PER_ELEMENT === 2 ? n.UNSIGNED_SHORT : n.UNSIGNED_INT;
n.drawElements(n.TRIANGLES, t.particleChildren.length * 6, u, 0);
}
}
class zt {
execute(e, t) {
const r = e.renderer, s = t.shader || e.defaultShader;
s.groups[0] = r.renderPipes.uniformBatch.getUniformBindGroup(e.localUniforms, !0), s.groups[1] = r.texture.getTextureBindGroup(t.texture);
const i = e.state, n = e.getBuffers(t);
r.encoder.draw({
geometry: n.geometry,
shader: t.shader || e.defaultShader,
state: i,
size: t.particleChildren.length * 6
});
}
}
function _e(o, e = null) {
const t = o * 6;
if (t > 65535 ? e || (e = new Uint32Array(t)) : e || (e = new Uint16Array(t)), e.length !== t)
throw new Error(`Out buffer length is incorrect, got ${e.length} and expected ${t}`);
for (let r = 0, s = 0; r < t; r += 6, s += 4)
e[r + 0] = s + 0, e[r + 1] = s + 1, e[r + 2] = s + 2, e[r + 3] = s + 0, e[r + 4] = s + 2, e[r + 5] = s + 3;
return e;
}
function Dt(o) {
return {
dynamicUpdate: be(o, !0),
staticUpdate: be(o, !1)
};
}
function be(o, e) {
const t = [];
t.push(`
var index = 0;
for (let i = 0; i < ps.length; ++i)
{
const p = ps[i];
`);
let r = 0;
for (const i in o) {
const n = o[i];
if (e !== n.dynamic)
continue;
t.push(`offset = index + ${r}`), t.push(n.code);
const a = J(n.format);
r += a.stride / 4;
}
t.push(`
index += stride * 4;
}
`), t.unshift(`
var stride = ${r};
`);
const s = t.join(`
`);
return new Function("ps", "f32v", "u32v", s);
}
class Ot {
constructor(e) {
this._size = 0, this._generateParticleUpdateCache = {};
const t = this._size = e.size ?? 1e3, r = e.properties;
let s = 0, i = 0;
for (const c in r) {
const d = r[c], h = J(d.format);
d.dynamic ? i += h.stride : s += h.stride;
}
this._dynamicStride = i / 4, this._staticStride = s / 4, this.staticAttributeBuffer = new E(t * 4 * s), this.dynamicAttributeBuffer = new E(t * 4 * i), this.indexBuffer = _e(t);
const n = new re();
let a = 0, l = 0;
this._staticBuffer = new O({
data: new Float32Arra