webgl-dsl
Version:
Thin functional WebGL wrapper with strong typed GLSL DSL
1,651 lines (1,650 loc) • 42.8 kB
JavaScript
const $ = /* @__PURE__ */ (() => {
let n = 0;
return function() {
return n++;
};
})();
var p = /* @__PURE__ */ ((n) => (n.Scalar = "float", n.Vector2 = "vec2", n.Matrix2 = "mat2", n.Vector3 = "vec3", n.Matrix3 = "mat3", n.Vector4 = "vec4", n.Matrix4 = "mat4", n.Boolean = "bool", n.Sampler = "sampler2D", n))(p || {}), de = /* @__PURE__ */ ((n) => (n.High = "highp", n.Medium = "mediump", n.Low = "lowp", n))(de || {});
((n) => {
function e(i) {
switch (i) {
case "bool":
case "float":
case "sampler2D":
return 1;
case "vec2":
case "mat2":
return 2;
case "vec3":
case "mat3":
return 3;
case "vec4":
case "mat4":
return 4;
}
}
n.size = e;
function r(i) {
switch (i) {
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
}
}
n.vector = r;
function a(i) {
switch (i) {
case 1:
return "float";
case 2:
return "vec2";
case 3:
return "vec3";
case 4:
return "vec4";
}
}
n.numeric = a;
function t(i) {
return i === "vec2" || i === "vec3" || i === "vec4";
}
n.isVector = t;
function s(i) {
return i === "mat2" || i === "mat3" || i === "mat4";
}
n.isMatrix = s;
})(p || (p = {}));
class x {
constructor(e = /* @__PURE__ */ new Map()) {
this.cache = e, this.global = "", this.local = "";
}
once(e, r) {
if (this.cache.has(e))
return this.cache.get(e);
{
const a = r();
return this.cache.set(e, a), a;
}
}
getGlobal() {
return this.global;
}
addGlobal(e) {
return this.global += e, this;
}
getLocal() {
return this.local;
}
addLocal(e) {
return this.local += e, this;
}
child() {
return new x(this.cache);
}
}
const fe = "==+-*/<><=>=!&&||", o = class o {
constructor(e) {
this.getValue = e;
}
static call(e, r, a) {
const t = fe.indexOf(e) !== -1, s = r.map((i) => typeof i == "number" ? v(i) : i);
return r.length === 2 && t ? new o((i) => {
const l = s.map((h) => h.getValue(i));
return {
type: a(l.map((h) => h.type)),
content: `((${l[0].content}) ${e} (${l[1].content}))`
};
}) : new o((i) => {
const l = s.map((h) => h.getValue(i));
return {
type: a(l.map((h) => h.type)),
content: `${e}(${l.map((h) => h.content).join(", ")})`
};
});
}
unary(e) {
return o.call(e, [this], (r) => r[0]);
}
sin() {
return this.unary("sin");
}
cos() {
return this.unary("cos");
}
radians() {
return this.unary("radians");
}
degrees() {
return this.unary("degrees");
}
tan() {
return this.unary("tan");
}
asin() {
return this.unary("asin");
}
acos() {
return this.unary("acos");
}
exp() {
return this.unary("exp");
}
log() {
return this.unary("log");
}
exp2() {
return this.unary("exp2");
}
log2() {
return this.unary("log2");
}
sqrt() {
return this.unary("sqrt");
}
inversesqrt() {
return this.unary("inversesqrt");
}
abs() {
return this.unary("abs");
}
sign() {
return this.unary("sign");
}
floor() {
return this.unary("floor");
}
ceil() {
return this.unary("ceil");
}
fract() {
return this.unary("fract");
}
normalize() {
return this.unary("normalize");
}
round() {
return this.add(0.5).floor();
}
not() {
return this.unary("!");
}
atan(e) {
return e === void 0 ? o.call(
"atan",
[this],
([r]) => r
) : o.call(
"atan",
[this, e],
(r) => r[0]
);
}
pow(e) {
const r = typeof e == "number" ? v(e) : e;
return o.call("pow", [this, r], ([a]) => a);
}
mod(e) {
const r = typeof e == "number" ? v(e) : e;
return o.call("mod", [this, r], ([a]) => a);
}
min(e) {
const r = typeof e == "number" ? v(e) : e;
return o.call("min", [this, r], ([a]) => a);
}
max(e) {
return o.call("max", [this, e], ([r]) => r);
}
mix(e, r) {
return o.call("mix", [this, e, r], ([a]) => a);
}
clamp(e, r) {
return o.call("clamp", [this, e, r], ([a]) => a);
}
smoothstep(e, r) {
return o.call("smoothstep", [e, r, this], ([a]) => a);
}
length() {
return o.call(
"length",
[this],
() => "float"
/* Scalar */
);
}
/**
* Distance to other point
*/
distance(e) {
return o.call(
"distance",
[this, e],
() => "float"
/* Scalar */
);
}
/**
* Dot product
*/
dot(e) {
return o.call(
"dot",
[this, e],
() => "float"
/* Scalar */
);
}
reflect(e) {
return o.call("reflect", [this, e], ([r]) => r);
}
refract(e, r) {
return o.call("refract", [this, e, r], ([a]) => a);
}
/**
* Get texture value at the specified point
*/
texture2D(e) {
return o.call(
"texture2D",
[this, e],
() => "vec4"
/* Vector4 */
);
}
/**
* Addition
*/
add(e) {
return o.call(
"+",
[this, e],
([r, a]) => r === "float" ? a : r
);
}
/**
* Substraction
*/
sub(e) {
return o.call(
"-",
[this, e],
([r, a]) => r === "float" ? a : r
);
}
/**
* Division
*/
div(e) {
return o.call(
"/",
[this, e],
([r, a]) => r === "float" ? a : r
);
}
/**
* Multiplication operation
*/
mul(e) {
return o.call("*", [this, e], ([r, a]) => r === "float" || r === a ? a : a === "float" || p.isVector(r) ? r : p.isVector(a) ? a : r);
}
bool(e, r) {
return o.call(
e,
[this, r],
() => "bool"
/* Boolean */
);
}
/** Less */
lt(e) {
return this.bool("<", e);
}
/** Greater */
gt(e) {
return this.bool(">", e);
}
/** Less or equal */
lte(e) {
return this.bool("<=", e);
}
/** Greater or equal */
gte(e) {
return this.bool(">=", e);
}
/** Equal */
eq(e) {
return this.bool("==", e);
}
/** Not equal */
neq(e) {
return this.bool("!=", e);
}
and(e) {
return o.call(
"&&",
[this, e],
() => "bool"
/* Boolean */
);
}
or(e) {
return o.call(
"||",
[this, e],
() => "bool"
/* Boolean */
);
}
/**
* Save some expression into a variable
*/
mem(e) {
const r = `mem${$()}`;
return new o((a) => {
const t = this.getValue(a);
return a.once(r, () => {
const s = t.type !== "bool";
a.addLocal(
`${s ? `${e} ` : ""}${t.type} ${r} = ${t.content};
`
);
}), {
type: t.type,
content: r
};
});
}
/**
* Save some expression with high quality into a variable
*/
memHQ() {
return this.mem(
"highp"
/* High */
);
}
/**
* Save some expression with medium quality into a variable
*/
memMQ() {
return this.mem(
"mediump"
/* Medium */
);
}
/**
* Save some expression with low quality into a variable
*/
memLQ() {
return this.mem(
"lowp"
/* Low */
);
}
/**
* Conditional expression
* @param precision Precision of the expression result
* @param whenTrue True brunch of the condition
* @param whenFalse False brunch of the condition
*/
cond(e, r, a) {
const t = `cond${$()}`;
let s = null;
return new o((i) => (i.once(t, () => {
const l = this.getValue(i), h = i.child(), c = r.getValue(h), d = i.child(), f = a.getValue(d);
s = c.type, i.addGlobal(h.getGlobal()).addGlobal(d.getGlobal()), i.addLocal(
`${c.type !== "bool" ? e + " " : ""}${c.type} ${t};
`
).addLocal(`if (${l.content}) {
`).addLocal(h.getLocal()).addLocal(`${t} = ${c.content};
`).addLocal(`} else {
`).addLocal(d.getLocal()).addLocal(`${t} = ${f.content};
`).addLocal(`}
`);
}), {
type: s,
content: t
}));
}
condHQ(e, r) {
return this.cond("highp", e, r);
}
condMQ(e, r) {
return this.cond("mediump", e, r);
}
condLQ(e, r) {
return this.cond("lowp", e, r);
}
/**
* Take one or more components from vector
*/
take(e, r, a, t) {
return new o((s) => {
const i = [e, r, a, t].filter(
(h) => h !== void 0
), l = this.getValue(s);
return {
type: i.length === 1 ? "float" : p.vector(i.length),
content: `(${l.content}).${i.map((h) => "xyzw".charAt(h)).join("")}`
};
});
}
vec2() {
return new o((e) => ({
type: "vec2",
content: `vec2(${this.getValue(e).content})`
}));
}
vec3() {
return new o((e) => ({
type: "vec3",
content: `vec3(${this.getValue(e).content})`
}));
}
vec4() {
return new o((e) => ({
type: "vec4",
content: `vec4(${this.getValue(e).content})`
}));
}
/**
* Get the first component of vector
*/
x() {
return this.take(0);
}
/**
* Get the second component of vector
*/
y() {
return this.take(1);
}
/**
* Get the third component of vector
*/
z() {
return this.take(2);
}
/**
* Get the fourth component of vector
*/
w() {
return this.take(3);
}
/**
* Get the first component of vector
*/
r() {
return this.take(0);
}
/**
* Get the second component of vector
*/
g() {
return this.take(1);
}
/**
* Get the third component of vector
*/
b() {
return this.take(2);
}
/**
* Get the fourth component of vector
*/
a() {
return this.take(3);
}
/**
* Create vector as a concatenation of current value and argument
*/
cat(e) {
return typeof e == "number" ? this.cat(o.val(e)) : new o((r) => {
const a = this.getValue(r), t = e.getValue(r), s = p.numeric(
p.size(a.type) + p.size(t.type)
);
return {
type: s,
content: `${s}(${a.content}, ${t.content})`
};
});
}
/**
* Wrap set of values into single GLSL value
*/
static val(...e) {
if (e.length === 1) {
if (typeof e[0] == "boolean")
return new o(() => ({
type: "bool",
content: e[0] ? "1" : "0"
}));
if (e[0] instanceof o)
return e[0];
{
const r = e[0].toString();
return new o(() => ({
type: "float",
content: /[e\.]/.test(r) ? r : `${r}.0`
}));
}
} else if (e.some((r) => typeof r == "number")) {
const r = e.map((a) => o.val(a));
return o.val.apply(null, r);
} else
return e.reduce((r, a) => r.cat(a));
}
};
o.PI = o.val(Math.PI);
let A = o;
var m;
((n) => {
function e(l) {
return Array.isArray(l) ? l[0] : l;
}
n.getType = e;
function r(l) {
return Array.isArray(l) ? l[1] : "highp";
}
n.getPrecision = r;
function a(l) {
return Object.keys(l).reduce(
(h, c) => (h[c] = e(l[c]), h),
{}
);
}
n.withoutPrecision = a;
function t(l, h) {
const c = {};
return Object.keys(h).forEach((d) => {
const f = h[d];
c[d] = new A((b) => (b.once(`types_map_value_${d}`, () => {
b.addGlobal(
`${l} ${n.getPrecision(f)} ${n.getType(f)} ${d};
`
);
}), {
type: n.getType(f),
content: d
}));
}), c;
}
n.values = t;
function s(l) {
let h = 0;
for (const c in l)
h += p.size(e(l[c]));
return h;
}
n.stride = s;
function i(l) {
const h = s(l);
return Object.keys(l).sort().reduce((c, d) => {
const f = c.length ? c[c.length - 1] : null;
return c.push({
name: d,
stride: h,
size: p.size(e(l[d])),
offset: f ? f.offset + f.size : 0
}), c;
}, []);
}
n.layout = i;
})(m || (m = {}));
function pe({
uniforms: n,
attributes: e,
varyings: r,
instances: a,
fragment: t,
vertex: s
}) {
const i = m.values("uniform", n), l = m.values("attribute", {
...e,
...a || {}
}), h = r ? m.values("varying", r) : {}, c = new x();
Object.keys(h).forEach((E) => {
h[E].getValue(c);
});
const d = s({
...i,
...l
}), f = Object.keys(d).map((E) => `${E} = ${d[E].getValue(c).content};
`).join(""), b = c.getGlobal() + `void main() {
` + c.getLocal() + f + `}
`, O = new x();
Object.keys(h).forEach((E) => {
h[E].getValue(c);
});
const oe = t({
...i,
...h,
gl_FragCoord: new A(() => ({
type: "vec4",
content: "gl_FragCoord"
})),
gl_PointCoord: new A(() => ({
type: "vec2",
content: "gl_FragCoord"
})),
gl_FrontFacing: new A(() => ({
type: "bool",
content: "gl_FrontFacing"
}))
}).gl_FragColor.getValue(O), ue = O.getGlobal() + `void main() {
` + O.getLocal() + `gl_FragColor = ${oe.content};
}
`;
return {
vertex: b,
fragment: ue,
uniforms: m.withoutPrecision(n),
attributes: m.withoutPrecision(e),
instances: m.withoutPrecision(a || {})
};
}
const v = A.val;
class me {
constructor(e, r, a) {
this.gl = e, this.primitivesType = r, this.source = a, this.textureInstances = /* @__PURE__ */ new Map(), this.textureIndexes = /* @__PURE__ */ new Map(), this.program = e.program(a.vertex, a.fragment), this.attributes = e.arrayBuffer(), this.instances = e.arrayBuffer(), this.elements = e.elementsBuffer(), this.attributesStride = m.stride(a.attributes), this.attributesLayout = m.layout(a.attributes), this.instancesStride = m.stride(a.instances), this.instancesLayout = m.layout(a.instances), this.attributesLayout.forEach((t) => {
this.program.setAttribute(
t.name,
this.attributes,
t.stride,
t.offset
);
}), this.instancesLayout.forEach((t) => {
this.program.setAttribute(
t.name,
this.instances,
t.stride,
t.offset
);
});
for (const t in a.uniforms)
m.getType(a.uniforms[t]) === p.Sampler && this.textureIndexes.set(t, this.textureIndexes.size);
}
prepareData(e, r, a) {
const t = new Float32Array(e * a.length);
return a.forEach((s, i) => {
r.forEach((l) => {
const h = s[l.name], c = e * i + l.offset;
if (Array.isArray(h))
for (let d = 0; d < h.length; d++)
t[c + d] = h[d];
else if (l.size === 1 && typeof h == "number")
t[c] = h;
else if (l.size === 2) {
const { x: d, y: f } = h;
t[c] = d, t[c + 1] = f;
} else if (l.size === 3) {
const { x: d, y: f, z: b } = h;
t[c] = d, t[c + 1] = f, t[c + 2] = b;
} else
throw new Error(
`Unsupported attribute '${l.name}' value: ${JSON.stringify(h)}`
);
});
}), t;
}
setAttributes(e) {
const r = this.prepareData(
this.attributesStride,
this.attributesLayout,
e
);
return this.attributes.setContent(r), this;
}
setInstances(e) {
const r = this.prepareData(
this.instancesStride,
this.instancesLayout,
e
);
return this.instances.setContent(r), this;
}
setElements(e) {
return this.elements.setContent(e), this;
}
setUniforms(e) {
const r = this.source.uniforms;
for (const a in e) {
const t = e[a];
let s;
if (typeof t == "number")
s = [t];
else if (Array.isArray(t))
s = t;
else if (t instanceof he) {
const i = this.textureIndexes.get(a);
this.textureInstances.set(i, t), s = [i];
} else if (r[a] === p.Vector2) {
const { x: i, y: l } = t;
s = [i, l];
} else if (r[a] === p.Vector3) {
const { x: i, y: l, z: h } = t;
s = [i, l, h];
} else
throw new Error(
`Invalid value for uniform '${a}', expected ${r[a]}`
);
this.program.setUniform(a, s);
}
return this;
}
draw(e = this.instancesStride ? this.instances.length / this.instancesStride : null, r = this.attributesStride ? this.attributes.length / this.attributesStride : null, a = this.elements.length) {
const t = this.gl;
t.settings().program(this.program).enabledAttributes(
Object.keys(this.program.attributes).map((s) => this.program.attributes[s]?.location).filter((s) => s != null)
).instancedAttributes(
this.instancesLayout.map((s) => s.name).map((s) => this.program.attributes[s]?.location).filter((s) => s != null)
).textures(
Array.from(this.textureInstances.entries()).reduce(
(s, [i, l]) => (s[i] = l, s),
new Array(16).fill(null)
)
).apply(() => {
if (e !== null && a !== 0)
t.settings().elementsBuffer(this.elements).apply(() => {
t.drawsInstancedElements(
this.primitivesType,
a,
e
);
});
else if (e !== null && r !== null)
t.drawInstancedArrays(
this.primitivesType,
r,
e
);
else if (a !== 0)
t.settings().elementsBuffer(this.elements).apply(() => {
t.drawsElements(
this.primitivesType,
a
);
});
else if (r)
t.drawArrays(this.primitivesType, r);
else
throw new Error("Invalid draw dataset");
});
}
dispose() {
this.program.dispose(), this.attributes.dispose(), this.instances.dispose(), this.elements.dispose();
}
}
function ge(n, e, r) {
return new me(
n,
e,
"vertex" in r && typeof r.vertex == "string" ? r : pe(r)
);
}
class Ae {
constructor(e) {
this.values = e;
}
dispose() {
this.values.forEach((e) => e.dispose());
}
}
function ye(...n) {
return new Ae(n);
}
function be(...n) {
n.forEach((e) => e.dispose());
}
function Ee(...n) {
const e = [];
try {
for (let r = 0; r < n.length; r++)
e.push(n[r](...e));
return e;
} catch (r) {
throw e.reverse().forEach((a) => a.dispose()), r;
}
}
var B;
((n) => {
n.join = ye, n.dispose = be, n.create = Ee;
})(B || (B = {}));
function we(n, e) {
try {
return e(n);
} finally {
n.dispose();
}
}
function Le(...n) {
const e = n.length - 1, r = [];
try {
for (let a = 0; a < e; a++)
r.push(n[a](...r));
return n[e](...r);
} finally {
r.reverse().forEach((a) => a.dispose());
}
}
const U = 256, P = 16384, ve = 0, Re = 1, xe = 2, Se = 3, Oe = 4, Te = 5, Ie = 6, Ne = 0, Ve = 1, Ce = 768, Me = 769, De = 770, $e = 771, Be = 772, Ue = 773, Pe = 774, _e = 775, Ge = 776, qe = 32774, ke = 32778, He = 32779, M = 34962, D = 34963, ze = 35040, We = 35044, Fe = 35048, je = 1028, Xe = 1029, Qe = 1032, _ = 2884, G = 3042, q = 2929, k = 3089, Ye = 0, Ze = 1280, Ke = 1281, Je = 1282, et = 1285, tt = 33901, R = 5121, H = 5123, T = 5126, te = 6406, re = 6407, ne = 6408, rt = 6409, nt = 6410, st = 35632, at = 35633, it = 35714, lt = 35718, ht = 35721, ct = 512, ot = 513, ut = 514, dt = 515, ft = 516, pt = 517, mt = 518, gt = 519, At = 9728, yt = 9729, z = 10240, W = 10241, bt = 10242, Et = 10243, g = 3553, wt = 33984, F = 33071, j = 35664, X = 35665, Q = 35666, Lt = 35670, Y = 35674, Z = 35675, K = 35676, vt = 35678, Rt = 35713, I = 36160, S = 36161, J = 33189, xt = 36064, St = 36096, Ot = 37440, Tt = 35904, It = 35907;
var se = /* @__PURE__ */ ((n) => (n[n.Front = je] = "Front", n[n.Back = Xe] = "Back", n[n.FrontAndBack = Qe] = "FrontAndBack", n))(se || {}), N = /* @__PURE__ */ ((n) => (n[n.Add = qe] = "Add", n[n.Sub = ke] = "Sub", n[n.RSub = He] = "RSub", n[n.Min = 32775] = "Min", n[n.Max = 32776] = "Max", n))(N || {}), ae = /* @__PURE__ */ ((n) => (n[n.Never = ct] = "Never", n[n.Less = ot] = "Less", n[n.Equal = ut] = "Equal", n[n.LEqual = dt] = "LEqual", n[n.Greater = ft] = "Greater", n[n.NotEqual = pt] = "NotEqual", n[n.GEqual = mt] = "GEqual", n[n.Always = gt] = "Always", n))(ae || {}), w = /* @__PURE__ */ ((n) => (n[n.Zero = Ne] = "Zero", n[n.One = Ve] = "One", n[n.SrcColor = Ce] = "SrcColor", n[n.OneMinusSrcColor = Me] = "OneMinusSrcColor", n[n.DstColor = Pe] = "DstColor", n[n.OneMinusDstColor = _e] = "OneMinusDstColor", n[n.SrcAlpha = De] = "SrcAlpha", n[n.OneMinusSrcAlpha = $e] = "OneMinusSrcAlpha", n[n.DstAlpha = Be] = "DstAlpha", n[n.OneMinusDstAlpha = Ue] = "OneMinusDstAlpha", n[n.SrcAlphaSaturate = Ge] = "SrcAlphaSaturate", n))(w || {}), ie = /* @__PURE__ */ ((n) => (n[n.Nearest = At] = "Nearest", n[n.Linear = yt] = "Linear", n))(ie || {}), le = /* @__PURE__ */ ((n) => (n[n.Alpha = te] = "Alpha", n[n.Luminance = rt] = "Luminance", n[n.LuminanceAlpha = nt] = "LuminanceAlpha", n[n.Rgb = re] = "Rgb", n[n.Rgba = ne] = "Rgba", n[n.Srgb = Tt] = "Srgb", n[n.Srgba = It] = "Srgba", n))(le || {}), y = /* @__PURE__ */ ((n) => (n[n.Rgba = ne] = "Rgba", n[n.Rgb = re] = "Rgb", n[n.Alpha = te] = "Alpha", n))(y || {});
((n) => {
function e(r) {
switch (r) {
case n.Rgb:
return 3;
case n.Rgba:
return 4;
case n.Alpha:
return 1;
}
}
n.getChannelsCount = e;
})(y || (y = {}));
var V = /* @__PURE__ */ ((n) => (n[n.Vertex = at] = "Vertex", n[n.Fragment = st] = "Fragment", n))(V || {}), Nt = /* @__PURE__ */ ((n) => (n[n.NoError = Ye] = "NoError", n[n.InvalidEnum = Ze] = "InvalidEnum", n[n.InvalidValue = Ke] = "InvalidValue", n[n.InvalidOperation = Je] = "InvalidOperation", n[n.OutOfMemory = et] = "OutOfMemory", n))(Nt || {}), L = /* @__PURE__ */ ((n) => (n[n.Stream = ze] = "Stream", n[n.Static = We] = "Static", n[n.Dynamic = Fe] = "Dynamic", n))(L || {}), Vt = /* @__PURE__ */ ((n) => (n[n.Array = M] = "Array", n[n.Elements = D] = "Elements", n))(Vt || {}), Ct = /* @__PURE__ */ ((n) => (n[n.Points = ve] = "Points", n[n.Lines = Re] = "Lines", n[n.LineStrip = Se] = "LineStrip", n[n.LineLoop = xe] = "LineLoop", n[n.Triangles = Oe] = "Triangles", n[n.TriangleStrip = Te] = "TriangleStrip", n[n.TriangleFan = Ie] = "TriangleFan", n))(Ct || {});
class Pt {
constructor(...e) {
this.settingsCache = C.initial();
const [r, a] = e;
typeof HTMLCanvasElement < "u" && r instanceof HTMLCanvasElement ? this.handle = r.getContext("webgl", a) : this.handle = r, this.instancedArraysExtension = this.handle.getExtension(
"ANGLE_instanced_arrays"
), this.minMaxExtension = this.handle.getExtension("EXT_blend_minmax"), this.srgbExtension = this.handle.getExtension("EXT_sRGB");
}
/**
* Get the width of the drawing buffer.
*/
get width() {
return this.handle.drawingBufferWidth;
}
/**
* Get the height of the drawing buffer.
*/
get height() {
return this.handle.drawingBufferHeight;
}
isContextLost() {
return this.handle.isContextLost();
}
getPointSizeRange() {
return this.handle.getParameter(tt);
}
clearColorBuffer() {
return this.handle.clear(P), this;
}
clearDepthBuffer() {
return this.handle.clear(U), this;
}
/**
* Clear color and depth buffer
*/
clearBuffers() {
return this.handle.clear(P | U), this;
}
/**
* Read pixels from a drawing buffer into an array buffer
*/
read(e = y.Rgba) {
const { width: r, height: a } = this, t = new Uint8Array(
r * a * y.getChannelsCount(e)
);
return this.settings().viewport(0, 0, r, a).apply(() => {
this.handle.readPixels(
0,
0,
r,
a,
e,
R,
t
);
}), t;
}
drawArrays(e, r) {
return this.handle.drawArrays(e, 0, r), this;
}
drawsElements(e, r) {
return this.handle.drawElements(
e,
r,
H,
0
), this;
}
drawInstancedArrays(e, r, a) {
return this.instancedArraysExtension.drawArraysInstancedANGLE(
e,
0,
r,
a
), this;
}
drawsInstancedElements(e, r, a) {
return this.instancedArraysExtension.drawElementsInstancedANGLE(
e,
r,
H,
0,
a
), this;
}
/**
* Create an empty settings object
*/
settings() {
return new u(this, this.settingsCache);
}
/**
* Create texture with specified parameters
*/
texture(e) {
return new he(this, e);
}
/**
* Create depth buffer with specified width and height
* @param width Depth buffer width
* @param height Depth buffer height
*/
renderBuffer(e, r) {
return new Mt(this, e, r);
}
/**
* Create a frame buffer that can be used as a render target.
* @param texture The texture to attach to the frame buffer.
* @param renderBuffer Depth buffer to attach to the frame buffer.
*/
frameBuffer(e, r) {
return new ce(this, e, r);
}
arrayBuffer(e = null, r = L.Dynamic) {
return new Dt(this, e, r);
}
elementsBuffer(e = null, r = L.Dynamic) {
return new $t(this, e, r);
}
/**
* Create a program with a specified vertex and fragment shader source
*/
program(e, r) {
return Le(
() => new ee(this, V.Vertex, e),
() => new ee(this, V.Fragment, r),
(a, t) => new Bt(this, a, t)
);
}
/**
* The main function of this library, creates a command with specified parameters and shaders
* @param primitivesType Type of primitives to draw
* @param configOrSource Description of attributes, uniforms, varyings, and shaders
*/
command(e, r) {
return ge(this, e, r);
}
hasSrgbExtension() {
return !!this.srgbExtension;
}
getErrorCode() {
return this.handle.getError();
}
/**
* Destroy WebGL context
*/
dispose() {
const e = this.handle.getExtension("WEBGL_lose_context");
e && e.loseContext();
}
}
var C;
((n) => {
n.initial = () => ({
blend: !1,
viewport: [0, 0, 0, 0],
scissorTest: !1,
scissorBox: [0, 0, 0, 0],
depthTest: !1,
depthFunction: ae.Less,
clearDepth: 1,
lineWidth: 1,
blendEquation: [N.Add, N.Add],
blendFunction: [
w.One,
w.Zero,
w.One,
w.Zero
],
clearColor: [0, 0, 0, 0],
activeTexture: 0,
textures: /* @__PURE__ */ new Map(),
arrayBuffer: null,
elementsBuffer: null,
program: null,
enabledAttributes: /* @__PURE__ */ new Set(),
instancedAttributes: /* @__PURE__ */ new Set(),
renderBuffer: null,
frameBuffer: null,
cullFace: !1,
cullFaceMode: se.Back
});
})(C || (C = {}));
class u {
constructor(e, r, a = (t) => t()) {
this.gl = e, this.cache = r, this.apply = a, this.blend = u.cached({
read: (t) => t.blend,
write: (t, s) => {
t.blend = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
s ? t.handle.enable(G) : t.handle.disable(G);
}
}), this.cullFace = u.cached({
read: (t) => t.cullFace,
write: (t, s) => {
t.cullFace = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
s ? t.handle.enable(_) : t.handle.disable(_);
}
}), this.cullFaceMode = u.cached({
read: (t) => t.cullFaceMode,
write: (t, s) => {
t.cullFaceMode = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.cullFace(s);
}
}), this.viewport = (() => {
const t = u.cached({
read: (s) => s.viewport,
write: (s, i) => {
s.viewport = i;
},
equals: (s, i) => s.every((l, h) => l === i[h]),
apply: (s, [i, l, h, c]) => {
s.handle.viewport(i, l, h, c);
}
});
return function(s, i, l, h) {
return t.call(this, [s, i, l, h]);
};
})(), this.scissorTest = u.cached({
read: (t) => t.scissorTest,
write: (t, s) => {
t.scissorTest = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
s ? t.handle.enable(k) : t.handle.disable(k);
}
}), this.scissorBox = (() => {
const t = u.cached({
read: (s) => s.scissorBox,
write: (s, i) => {
s.scissorBox = i;
},
equals: (s, i) => s.every((l, h) => l === i[h]),
apply: (s, [i, l, h, c]) => {
s.handle.scissor(i, l, h, c);
}
});
return function(s, i, l, h) {
return t.call(this, [s, i, l, h]);
};
})(), this.depthTest = u.cached({
read: (t) => t.depthTest,
write: (t, s) => {
t.depthTest = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
s ? t.handle.enable(q) : t.handle.disable(q);
}
}), this.clearDepth = u.cached({
read: (t) => t.clearDepth,
write: (t, s) => {
t.clearDepth = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.clearDepth(s);
}
}), this.lineWidth = u.cached({
read: (t) => t.lineWidth,
write: (t, s) => {
t.lineWidth = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.lineWidth(s);
}
}), this.blendEquation = (() => {
const t = u.cached({
read: (s) => s.blendEquation,
write: (s, i) => {
s.blendEquation = i;
},
equals: (s, i) => s.every((l, h) => l === i[h]),
apply: (s, [i, l]) => {
s.handle.blendEquationSeparate(i, l);
}
});
return function(s, i = s) {
return t.call(this, [s, i]);
};
})(), this.blendFunction = (() => {
const t = u.cached({
read: (s) => s.blendFunction,
write: (s, i) => {
s.blendFunction = i;
},
equals: (s, i) => s.every((l, h) => l === i[h]),
apply: (s, [i, l, h, c]) => {
s.handle.blendFuncSeparate(i, l, h, c);
}
});
return function(s, i, l = s, h = i) {
return t.call(this, [s, i, l, h]);
};
})(), this.depthFunction = u.cached({
read: (t) => t.depthFunction,
write: (t, s) => {
t.depthFunction = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.depthFunc(s);
}
}), this.clearColor = (() => {
const t = u.cached({
read: (s) => s.clearColor,
write: (s, i) => {
s.clearColor = i;
},
equals: (s, i) => s.every((l, h) => l === i[h]),
apply: (s, [i, l, h, c]) => {
s.handle.clearColor(i, l, h, c);
}
});
return function(s, i, l, h) {
return t.call(this, [s, i, l, h]);
};
})(), this.activeTexture = u.cached({
read: (t) => t.activeTexture,
write: (t, s) => {
t.activeTexture = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.activeTexture(wt + s);
}
}), this.texture = (() => {
const t = new Array(16).fill(null).map((s, i) => u.cached({
read: (l) => l.textures.get(i) || null,
write: (l, h) => {
h ? l.textures.set(i, h) : l.textures.delete(i);
},
equals: (l, h) => l === h,
apply: (l, h) => {
l.settings().activeTexture(i).apply(() => {
l.handle.bindTexture(
g,
h?.handle || null
);
});
}
}));
return function(s, i) {
return t[s].call(this, i);
};
})(), this.arrayBuffer = u.cached({
read: (t) => t.arrayBuffer,
write: (t, s) => {
t.arrayBuffer = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.bindBuffer(M, s?.handle ?? null);
}
}), this.elementsBuffer = u.cached({
read: (t) => t.elementsBuffer,
write: (t, s) => {
t.elementsBuffer = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.bindBuffer(D, s?.handle ?? null);
}
}), this.program = u.cached({
read: (t) => t.program,
write: (t, s) => {
t.program = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.useProgram(s ? s.handle : null);
}
}), this.renderBuffer = u.cached({
read: (t) => t.renderBuffer,
write: (t, s) => {
t.renderBuffer = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.bindRenderbuffer(
S,
s ? s.handle : null
);
}
}), this.frameBuffer = u.cached({
read: (t) => t.frameBuffer,
write: (t, s) => {
t.frameBuffer = s;
},
equals: (t, s) => t === s,
apply: (t, s) => {
t.handle.bindFramebuffer(I, s ? s.handle : null);
}
});
}
static cached({
read: e,
write: r,
equals: a,
apply: t
}) {
return function(s) {
return this.then(
new u(this.gl, this.cache, (i) => {
const l = e(this.cache);
if (a(l, s))
return i();
try {
return r(this.cache, s), t(this.gl, s), i();
} finally {
r(this.cache, l), t(this.gl, l);
}
})
);
};
}
then(e) {
return new u(this.gl, this.cache, (r) => this.apply(() => e.apply(r)));
}
textures(e) {
let r = this;
for (let a = 0; a < 16; a++)
r = r.texture(
a,
a >= e.length ? null : e[a]
);
return r;
}
enabledAttributes(e) {
return this.then(
new u(this.gl, this.cache, (r) => {
const a = this.gl.handle, t = this.cache.enabledAttributes, s = new Set(e);
this.cache.enabledAttributes = s;
const i = (l, h) => {
l.forEach((c) => {
h.has(c) || a.disableVertexAttribArray(c);
}), h.forEach((c) => {
l.has(c) || a.enableVertexAttribArray(c);
});
};
try {
return i(t, s), r();
} finally {
i(s, t), this.cache.enabledAttributes = t;
}
})
);
}
instancedAttributes(e) {
return this.then(
new u(this.gl, this.cache, (r) => {
const a = this.gl.instancedArraysExtension, t = this.cache.instancedAttributes, s = new Set(e);
this.cache.instancedAttributes = s;
const i = (l, h) => {
l.forEach((c) => {
h.has(c) || a.vertexAttribDivisorANGLE(c, 0);
}), h.forEach((c) => {
l.has(c) || a.vertexAttribDivisorANGLE(c, 1);
});
};
try {
return i(t, s), r();
} finally {
i(s, t), this.cache.instancedAttributes = t;
}
})
);
}
renderTarget(e) {
return new u(this.gl, this.cache, (r) => we(new ce(this.gl, e), (a) => this.gl.settings().frameBuffer(a).viewport(0, 0, e.width, e.height).apply(r)));
}
}
class he {
constructor(e, r) {
this.gl = e, this.handle = e.handle.createTexture(), this.format = r.format || le.Rgba, this.filter = r.filter || ie.Nearest, "image" in r ? (this.width = r.image instanceof HTMLImageElement ? r.image.naturalWidth : r.image instanceof VideoFrame ? r.image.codedWidth : r.image.width, this.height = r.image instanceof HTMLImageElement ? r.image.naturalHeight : r.image instanceof VideoFrame ? r.image.codedHeight : r.image.height) : (this.width = r.width, this.height = r.height), e.settings().activeTexture(0).texture(0, this).apply(() => {
e.handle.pixelStorei(Ot, 1), e.handle.texParameteri(
g,
z,
this.filter
), e.handle.texParameteri(
g,
W,
this.filter
), e.handle.texParameteri(
g,
bt,
F
), e.handle.texParameteri(
g,
Et,
F
), "image" in r ? e.handle.texImage2D(
g,
0,
this.format,
this.format,
R,
r.image
) : e.handle.texImage2D(
g,
0,
this.format,
this.width,
this.height,
0,
// border
this.format,
R,
"data" in r ? r.data : null
);
});
}
/**
* Read pixels from the texture into an array buffer
*/
read(e = y.Rgba) {
const r = new Uint8Array(
this.width * this.height * y.getChannelsCount(e)
);
return this.gl.settings().renderTarget(this).viewport(0, 0, this.width, this.height).apply(() => {
this.gl.handle.readPixels(
0,
0,
this.width,
this.height,
e,
R,
r
);
}), r;
}
setFilter(e) {
this.gl.handle.texParameteri(g, z, e), this.gl.handle.texParameteri(g, W, e);
}
dispose() {
this.gl.handle.deleteTexture(this.handle);
}
}
class ce {
constructor(e, r, a) {
this.gl = e, this.colorBuffer = r, this.depthBuffer = a, this.handle = e.handle.createFramebuffer(), e.settings().frameBuffer(this).apply(() => {
e.handle.framebufferTexture2D(
I,
xt,
g,
r.handle,
0
), a && e.handle.framebufferRenderbuffer(
I,
St,
S,
a.handle
);
});
}
dispose() {
this.gl.handle.deleteFramebuffer(this.handle);
}
}
class Mt {
constructor(e, r, a) {
this.gl = e, this.widthValue = r, this.heightValue = a, this.handle = e.handle.createRenderbuffer(), e.settings().renderBuffer(this).apply(() => {
e.handle.renderbufferStorage(
S,
J,
r,
a
);
});
}
get width() {
return this.widthValue;
}
get height() {
return this.heightValue;
}
resize(e, r) {
const { gl: a } = this;
return (e !== this.width || r !== this.height) && (this.widthValue = e, this.heightValue = r, a.settings().renderBuffer(this).apply(() => {
a.handle.renderbufferStorage(
S,
J,
e,
r
);
})), this;
}
dispose() {
this.gl.handle.deleteRenderbuffer(this.handle);
}
}
class Dt {
constructor(e, r = null, a = L.Dynamic) {
this.gl = e, this.usage = a, this.lengthValue = 0, this.handle = e.handle.createBuffer(), r && this.setContent(r);
}
get length() {
return this.lengthValue;
}
setContent(e) {
const r = e instanceof Float32Array ? e : new Float32Array(e);
this.lengthValue = r.length;
const a = this.gl;
return a.settings().arrayBuffer(this).apply(() => {
a.handle.bufferData(M, r, this.usage);
}), this;
}
dispose() {
this.gl.handle.deleteBuffer(this.handle);
}
}
class $t {
constructor(e, r = null, a = L.Dynamic) {
this.gl = e, this.usage = a, this.lengthValue = 0, this.handle = e.handle.createBuffer(), r && this.setContent(r);
}
get length() {
return this.lengthValue;
}
setContent(e) {
const r = e instanceof Uint8Array || e instanceof Uint16Array ? e : new Uint16Array(e);
this.lengthValue = r.length;
const a = this.gl;
return a.settings().elementsBuffer(this).apply(() => {
a.handle.bufferData(D, r, this.usage);
}), this;
}
dispose() {
this.gl.handle.deleteBuffer(this.handle);
}
}
class ee {
constructor(e, r, a) {
this.gl = e, this.type = r, this.source = a;
const t = this.handle = e.handle.createShader(r);
if (e.handle.shaderSource(t, a), e.handle.compileShader(t), e.handle.getShaderParameter(t, Rt) === !1)
throw new Error(
`WebGL error '${e.handle.getShaderInfoLog(t)}' in '${a}'`
);
}
dispose() {
this.gl.handle.deleteShader(this.handle);
}
}
class Bt {
constructor(e, r, a) {
this.gl = e, this.vertex = r, this.fragment = a, this.uniforms = {}, this.attributes = {};
const t = this.handle = e.handle.createProgram();
if (e.handle.attachShader(t, r.handle), e.handle.attachShader(t, a.handle), e.handle.linkProgram(t), e.handle.validateProgram(t), e.handle.getProgramParameter(t, it) === !1)
throw new Error(
e.handle.getProgramInfoLog(t) || `Program linking error:
${r.source};
${a.source}`
);
const s = e.handle.getProgramParameter(
t,
lt
);
for (let l = 0; l < s; l++) {
const h = e.handle.getActiveUniform(t, l);
h !== null && (this.uniforms[h.name] = {
type: h.type,
location: e.handle.getUniformLocation(t, h.name),
size: h.size
});
}
const i = e.handle.getProgramParameter(
t,
ht
);
for (let l = 0; l < i; l++) {
const h = e.handle.getActiveAttrib(t, l);
h != null && (this.attributes[h.name] = {
type: h.type,
location: l,
size: h.size
});
}
}
setUniform(e, r) {
const { gl: a, uniforms: t } = this, s = t[e];
if (s) {
const { location: i, type: l } = s;
a.settings().program(this).apply(() => {
switch (l) {
case Lt:
a.handle.uniform1i(i, r[0] ? 1 : 0);
break;
case vt:
a.handle.uniform1iv(i, r);
break;
case T:
a.handle.uniform1fv(i, r);
break;
case j:
a.handle.uniform2fv(i, r);
break;
case X:
a.handle.uniform3fv(i, r);
break;
case Q:
a.handle.uniform4fv(i, r);
break;
case Y:
a.handle.uniformMatrix2fv(i, !1, r);
break;
case Z:
a.handle.uniformMatrix3fv(i, !1, r);
break;
case K:
a.handle.uniformMatrix4fv(i, !1, r);
break;
}
});
}
}
setAttribute(e, r, a, t) {
const s = this.attributes[e];
if (s != null) {
const { gl: i } = this;
i.settings().arrayBuffer(r).apply(() => {
i.handle.vertexAttribPointer(
s.location,
(() => {
switch (s.type) {
case T:
return 1;
case j:
return 2;
case X:
return 3;
case Q:
return 4;
case Y:
return 4;
case Z:
return 9;
case K:
return 16;
default:
throw new Error(
`Invalid attribute type '${s.type}'`
);
}
})(),
T,
!1,
a * 4,
t * 4
);
});
} else
console.warn(`Attribute '${e}' not found`);
}
dispose() {
this.gl.handle.deleteProgram(this.handle);
}
}
export {
Dt as ArrayBuffer,
N as BlendEquation,
w as BlendFunction,
Vt as BufferTarget,
L as BufferUsage,
me as Command,
ae as DepthFunction,
B as Disposable,
$t as ElementsBuffer,
Nt as ErrorCode,
se as FaceCulling,
ce as FrameBuffer,
Pt as Gl,
A as Glsl,
x as GlslBuilder,
y as PixelFormat,
de as Precision,
Ct as PrimitivesType,
Bt as Program,
Mt as RenderBuffer,
u as Settings,
V as ShaderType,
he as Texture,
ie as TextureFilter,
le as TextureFormat,
p as Type,
m as TypeMap,
ge as command,
Ee as create,
be as dispose,
pe as source,
we as use,
Le as uses,
v as val
};
//# sourceMappingURL=index.js.map