vireglass 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/{chunk-2XJJO7SC.js → chunk-PM2SWCSF.js} +2 -2
- package/dist/{chunk-2XJJO7SC.js.map → chunk-PM2SWCSF.js.map} +1 -1
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -1
- package/dist/web/index.cjs +261 -151
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +88 -2
- package/dist/web/index.d.ts +88 -2
- package/dist/web/index.js +254 -153
- package/dist/web/index.js.map +1 -1
- package/package.json +4 -2
- package/src/dom/index.ts +6 -5
- package/src/targets/glsl.ts +4 -0
- package/src/web/gl.ts +57 -4
- package/src/web/gpu-timer.ts +111 -0
- package/src/web/index.ts +1 -0
- package/src/web/renderer.ts +305 -218
package/dist/index.d.cts
CHANGED
|
@@ -288,6 +288,10 @@ declare function convertReturns(mainBody: string): string;
|
|
|
288
288
|
* origin, y up. The flip via `u_resolution.y - gl_FragCoord.y` restores the original convention
|
|
289
289
|
* (both coordinate systems center the pixel at `+0.5`, so no X shift or constant is needed).
|
|
290
290
|
* `out vec4 fragColor` and `uniform vec2 u_resolution` are declared in the prologue (`addPrologue`).
|
|
291
|
+
*
|
|
292
|
+
* `xy` and `.eval()` are flipped together — but only inside a shader THIS function translates. A
|
|
293
|
+
* `VireGlassBackdropPass` (`web/renderer.ts`) that reads its own previous frame from an FBO is raw
|
|
294
|
+
* `gl_FragCoord`, unflipped; reusing AGSL-style helpers there needs an explicit flip of its own.
|
|
291
295
|
*/
|
|
292
296
|
declare function convertEntryPoint(src: string): string;
|
|
293
297
|
/** `#version 300 es` + `precision highp float;` — no equivalent in AGSL, WebGL2 requires them as
|
package/dist/index.d.ts
CHANGED
|
@@ -288,6 +288,10 @@ declare function convertReturns(mainBody: string): string;
|
|
|
288
288
|
* origin, y up. The flip via `u_resolution.y - gl_FragCoord.y` restores the original convention
|
|
289
289
|
* (both coordinate systems center the pixel at `+0.5`, so no X shift or constant is needed).
|
|
290
290
|
* `out vec4 fragColor` and `uniform vec2 u_resolution` are declared in the prologue (`addPrologue`).
|
|
291
|
+
*
|
|
292
|
+
* `xy` and `.eval()` are flipped together — but only inside a shader THIS function translates. A
|
|
293
|
+
* `VireGlassBackdropPass` (`web/renderer.ts`) that reads its own previous frame from an FBO is raw
|
|
294
|
+
* `gl_FragCoord`, unflipped; reusing AGSL-style helpers there needs an explicit flip of its own.
|
|
291
295
|
*/
|
|
292
296
|
declare function convertEntryPoint(src: string): string;
|
|
293
297
|
/** `#version 300 es` + `precision highp float;` — no equivalent in AGSL, WebGL2 requires them as
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { SURFACE_SHADER, addPrologue, convertEntryPoint, convertEvalCalls, convertHalfTypes, convertReturns, convertShaderUniforms, convertVecTypes, toGLSL } from './chunk-
|
|
1
|
+
export { SURFACE_SHADER, addPrologue, convertEntryPoint, convertEvalCalls, convertHalfTypes, convertReturns, convertShaderUniforms, convertVecTypes, toGLSL } from './chunk-PM2SWCSF.js';
|
|
2
2
|
export { GLASS_SCALE_DEFAULT, GRADIENT, NO_ACCESSIBILITY, SCROLL_EDGE_ENGAGE_DP, SETTLE, SMOOTH, accentAmount, accentTone, aggregate, applyAccessibility, applyAppear, applyGlassScale, concentricFit, concentricInset, concentricRadius, contrastRimLuma, createDeform, createGroupState, elasticAllowed, probeValuesAt, raiseIntoGlass, resolveShape, scrollEdgeReachDp, scrollEdgeStrength, scrollEdgeStyle, shadowTint, smoothPlane } from './chunk-CTTZNZFV.js';
|
|
3
3
|
export { CONFIRMATIONS, FADE_MS, FLIP_LUMA, INK_DARK, INK_LIGHT, RETURN_LUMA, ambientFrom, decisiveLuma, shouldInkBeLight } from './chunk-JNRZNMJJ.js';
|
|
4
4
|
export { ACCENT_AMOUNT, ADAPT_RADIUS, ALL_EFFECTS_ON, DEBUG_MODES, DYNAMIC_UNIFORMS, EFFECTS, FRESNEL_EXPONENT, ICON_UNIFORMS, LEGACY_NAMES, LEGACY_OPTICS, LENS_SHADER, MATERIAL_PRESETS, MATERIAL_RANGES, OVERLAY_UNIFORMS, PRESET_NAMES, PRODUCT_DIM, REST_LIGHT, SURFACE_LENGTH_UNIFORMS, VG_FALLOFF, VG_SDF, VIREGLASS_CLEAR_MATERIAL, VIREGLASS_CONTROL_MATERIAL, VIREGLASS_LYRICS_MATERIAL, VIREGLASS_MATERIAL, VIREGLASS_MATERIAL_V4, VIREGLASS_MATERIAL_V5, VIREGLASS_SHEET_MATERIAL, absorption, activeMaterial, applyToggles, blur, bodyDensity, colorPickup, debugIndex, diffraction, dispersion, edgeDensity, edgeLight, fresnelF0, fresnelStrength, gatherRadius, iorSpread, iridescence, lensMagnify, materialForInk, mediumTint, morphBetween, morphOutOf, neckToBridge, refractionScale, refractionStrength, resolveMaterial, resolveOptics, sceneDistance, sceneGradient, sdfRoundedRect, sdfRoundedRectGradient, smin, specularPower, specularStrength, toDeviceSurfaceUniforms, toLensProps, toSurfaceUniforms, touchWarp } from './chunk-H5QTBF67.js';
|
package/dist/web/index.cjs
CHANGED
|
@@ -1546,6 +1546,7 @@ function createTexture(gl, options) {
|
|
|
1546
1546
|
const internalFormat = options.internalFormat ?? gl.RGBA8;
|
|
1547
1547
|
const format = options.format ?? gl.RGBA;
|
|
1548
1548
|
const type = options.type ?? gl.UNSIGNED_BYTE;
|
|
1549
|
+
const wrap = options.wrap ?? gl.CLAMP_TO_EDGE;
|
|
1549
1550
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
1550
1551
|
gl.texImage2D(
|
|
1551
1552
|
gl.TEXTURE_2D,
|
|
@@ -1560,11 +1561,45 @@ function createTexture(gl, options) {
|
|
|
1560
1561
|
);
|
|
1561
1562
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
1562
1563
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
1563
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S,
|
|
1564
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T,
|
|
1564
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
|
|
1565
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
|
|
1565
1566
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
1566
1567
|
return texture;
|
|
1567
1568
|
}
|
|
1569
|
+
function locationCache(gl, program) {
|
|
1570
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1571
|
+
return (name) => {
|
|
1572
|
+
let loc = cache.get(name);
|
|
1573
|
+
if (loc === void 0) {
|
|
1574
|
+
loc = gl.getUniformLocation(program, name);
|
|
1575
|
+
cache.set(name, loc);
|
|
1576
|
+
}
|
|
1577
|
+
return loc;
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
function setUniform(gl, loc, value) {
|
|
1581
|
+
if (!loc) return;
|
|
1582
|
+
if (typeof value === "number") {
|
|
1583
|
+
gl.uniform1f(loc, value);
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
switch (value.length) {
|
|
1587
|
+
case 1:
|
|
1588
|
+
gl.uniform1f(loc, value[0]);
|
|
1589
|
+
break;
|
|
1590
|
+
case 2:
|
|
1591
|
+
gl.uniform2f(loc, value[0], value[1]);
|
|
1592
|
+
break;
|
|
1593
|
+
case 3:
|
|
1594
|
+
gl.uniform3f(loc, value[0], value[1], value[2]);
|
|
1595
|
+
break;
|
|
1596
|
+
case 4:
|
|
1597
|
+
gl.uniform4f(loc, value[0], value[1], value[2], value[3]);
|
|
1598
|
+
break;
|
|
1599
|
+
default:
|
|
1600
|
+
throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1568
1603
|
function createFramebuffer(gl, texture) {
|
|
1569
1604
|
const fbo = gl.createFramebuffer();
|
|
1570
1605
|
if (!fbo) throw new Error("vireglass/web: gl.createFramebuffer returned null");
|
|
@@ -1584,6 +1619,62 @@ function bindTextureAt(gl, unit, texture, program, uniformName) {
|
|
|
1584
1619
|
gl.uniform1i(loc, unit);
|
|
1585
1620
|
}
|
|
1586
1621
|
|
|
1622
|
+
// src/web/gpu-timer.ts
|
|
1623
|
+
var GPU_TIMER_RING_SIZE = 3;
|
|
1624
|
+
function createGpuTimer(gl) {
|
|
1625
|
+
const ext = gl.getExtension("EXT_disjoint_timer_query_webgl2");
|
|
1626
|
+
const slots = ext ? Array.from({ length: GPU_TIMER_RING_SIZE }, () => ({
|
|
1627
|
+
query: gl.createQuery(),
|
|
1628
|
+
pending: false
|
|
1629
|
+
})) : [];
|
|
1630
|
+
let cursor = 0;
|
|
1631
|
+
let active = null;
|
|
1632
|
+
let lastMs = null;
|
|
1633
|
+
function poll() {
|
|
1634
|
+
if (!ext) return;
|
|
1635
|
+
for (const slot of slots) {
|
|
1636
|
+
if (!slot.pending) continue;
|
|
1637
|
+
if (!gl.getQueryParameter(slot.query, gl.QUERY_RESULT_AVAILABLE)) continue;
|
|
1638
|
+
slot.pending = false;
|
|
1639
|
+
if (gl.getParameter(ext.GPU_DISJOINT_EXT)) continue;
|
|
1640
|
+
const ns = gl.getQueryParameter(slot.query, gl.QUERY_RESULT);
|
|
1641
|
+
lastMs = ns / 1e6;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
function begin() {
|
|
1645
|
+
active = null;
|
|
1646
|
+
if (!ext || slots.length === 0) return;
|
|
1647
|
+
poll();
|
|
1648
|
+
const slot = slots[cursor];
|
|
1649
|
+
if (slot.pending) return;
|
|
1650
|
+
gl.beginQuery(ext.TIME_ELAPSED_EXT, slot.query);
|
|
1651
|
+
active = slot;
|
|
1652
|
+
}
|
|
1653
|
+
function end() {
|
|
1654
|
+
if (!ext || !active) return;
|
|
1655
|
+
gl.endQuery(ext.TIME_ELAPSED_EXT);
|
|
1656
|
+
active.pending = true;
|
|
1657
|
+
cursor = (cursor + 1) % slots.length;
|
|
1658
|
+
active = null;
|
|
1659
|
+
}
|
|
1660
|
+
function time(fn) {
|
|
1661
|
+
begin();
|
|
1662
|
+
try {
|
|
1663
|
+
return fn();
|
|
1664
|
+
} finally {
|
|
1665
|
+
end();
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function getLastMs() {
|
|
1669
|
+
poll();
|
|
1670
|
+
return lastMs;
|
|
1671
|
+
}
|
|
1672
|
+
function destroy() {
|
|
1673
|
+
for (const slot of slots) gl.deleteQuery(slot.query);
|
|
1674
|
+
}
|
|
1675
|
+
return { time, getLastMs, destroy };
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1587
1678
|
// src/web/probe.ts
|
|
1588
1679
|
var PROBE_GRID_WIDTH = 48;
|
|
1589
1680
|
var PROBE_GRID_HEIGHT = 96;
|
|
@@ -1804,40 +1895,6 @@ void main() {
|
|
|
1804
1895
|
fragColor = texture(u_content, uv);
|
|
1805
1896
|
}
|
|
1806
1897
|
`;
|
|
1807
|
-
function locationCache(gl, program) {
|
|
1808
|
-
const cache = /* @__PURE__ */ new Map();
|
|
1809
|
-
return (name) => {
|
|
1810
|
-
let loc = cache.get(name);
|
|
1811
|
-
if (loc === void 0) {
|
|
1812
|
-
loc = gl.getUniformLocation(program, name);
|
|
1813
|
-
cache.set(name, loc);
|
|
1814
|
-
}
|
|
1815
|
-
return loc;
|
|
1816
|
-
};
|
|
1817
|
-
}
|
|
1818
|
-
function setUniform(gl, loc, value) {
|
|
1819
|
-
if (!loc) return;
|
|
1820
|
-
if (typeof value === "number") {
|
|
1821
|
-
gl.uniform1f(loc, value);
|
|
1822
|
-
return;
|
|
1823
|
-
}
|
|
1824
|
-
switch (value.length) {
|
|
1825
|
-
case 1:
|
|
1826
|
-
gl.uniform1f(loc, value[0]);
|
|
1827
|
-
break;
|
|
1828
|
-
case 2:
|
|
1829
|
-
gl.uniform2f(loc, value[0], value[1]);
|
|
1830
|
-
break;
|
|
1831
|
-
case 3:
|
|
1832
|
-
gl.uniform3f(loc, value[0], value[1], value[2]);
|
|
1833
|
-
break;
|
|
1834
|
-
case 4:
|
|
1835
|
-
gl.uniform4f(loc, value[0], value[1], value[2], value[3]);
|
|
1836
|
-
break;
|
|
1837
|
-
default:
|
|
1838
|
-
throw new Error(`vireglass/web: unsupported uniform size (${value.length})`);
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
1898
|
function applyChannel(gl, get, names, sizes, values) {
|
|
1842
1899
|
let cursor = 0;
|
|
1843
1900
|
for (let i = 0; i < names.length; i += 1) {
|
|
@@ -1900,6 +1957,12 @@ function createVireGlassRenderer(canvas) {
|
|
|
1900
1957
|
width: Math.max(width, 1),
|
|
1901
1958
|
height: Math.max(height, 1)
|
|
1902
1959
|
});
|
|
1960
|
+
let backdropFbo = null;
|
|
1961
|
+
function ensureBackdropFbo() {
|
|
1962
|
+
if (!backdropFbo) backdropFbo = createFramebuffer(gl, contentTexture);
|
|
1963
|
+
return backdropFbo;
|
|
1964
|
+
}
|
|
1965
|
+
const gpuTimer = createGpuTimer(gl);
|
|
1903
1966
|
const iconTexture = createTexture(gl, { width: 1, height: 1 });
|
|
1904
1967
|
const colorTexture = createTexture(gl, { width: 1, height: 1 });
|
|
1905
1968
|
gl.bindTexture(gl.TEXTURE_2D, iconTexture);
|
|
@@ -1928,128 +1991,164 @@ function createVireGlassRenderer(canvas) {
|
|
|
1928
1991
|
if (!sceneCtx) throw new Error("vireglass/web: scene 2D context unavailable");
|
|
1929
1992
|
gl.deleteTexture(contentTexture);
|
|
1930
1993
|
contentTexture = createTexture(gl, { width, height });
|
|
1994
|
+
if (backdropFbo) {
|
|
1995
|
+
gl.deleteFramebuffer(backdropFbo);
|
|
1996
|
+
backdropFbo = null;
|
|
1997
|
+
}
|
|
1931
1998
|
}
|
|
1932
1999
|
function render(options) {
|
|
1933
2000
|
if (!sceneCtx) throw new Error("vireglass/web: renderer not initialized (resize was never called)");
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
if (options.colorLayer) {
|
|
1940
|
-
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
1941
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);
|
|
2001
|
+
const ctx = sceneCtx;
|
|
2002
|
+
if (options.backdrop && options.scene) {
|
|
2003
|
+
throw new Error(
|
|
2004
|
+
"vireglass/web: render() needs exactly one of options.scene or options.backdrop, not both"
|
|
2005
|
+
);
|
|
1942
2006
|
}
|
|
1943
|
-
if (options.
|
|
1944
|
-
|
|
1945
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);
|
|
1946
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2007
|
+
if (!options.backdrop && !options.scene) {
|
|
2008
|
+
throw new Error("vireglass/web: render() needs either options.scene or options.backdrop");
|
|
1947
2009
|
}
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
const stats = fresh ? settleStats(index, fresh) : null;
|
|
1969
|
-
probes.push(stats);
|
|
1970
|
-
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
1971
|
-
gl.viewport(0, 0, width, height);
|
|
1972
|
-
gl.enable(gl.BLEND);
|
|
1973
|
-
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
1974
|
-
const reachOf = (m) => m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;
|
|
1975
|
-
const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));
|
|
1976
|
-
const touchReach = piece.touch ? Math.hypot(piece.touch.pullX, piece.touch.pullY) + piece.touch.waveAmp * 2 + Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press : 0;
|
|
1977
|
-
const padPx = (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) * options.density;
|
|
1978
|
-
const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));
|
|
1979
|
-
const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));
|
|
1980
|
-
const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));
|
|
1981
|
-
const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));
|
|
1982
|
-
gl.enable(gl.SCISSOR_TEST);
|
|
1983
|
-
gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));
|
|
1984
|
-
gl.useProgram(lensProgram);
|
|
1985
|
-
bindTextureAt(gl, 0, contentTexture, lensProgram, "content");
|
|
1986
|
-
setUniform(gl, lensLoc("u_contentSize"), [width, height]);
|
|
1987
|
-
setUniform(gl, lensLoc("u_resolution"), [width, height]);
|
|
1988
|
-
setUniform(gl, lensLoc("u_center"), [piece.centerX, piece.centerY]);
|
|
1989
|
-
setUniform(gl, lensLoc("u_reach"), Math.max(width, height));
|
|
1990
|
-
setUniform(gl, lensLoc("u_contentMin"), [1, 1]);
|
|
1991
|
-
setUniform(gl, lensLoc("u_contentMax"), [width - 1, height - 1]);
|
|
1992
|
-
if (stats) {
|
|
1993
|
-
setUniform(gl, lensLoc("u_probeLuma"), stats.luma);
|
|
1994
|
-
setUniform(gl, lensLoc("u_probeBusy"), stats.busy);
|
|
1995
|
-
setUniform(gl, lensLoc("u_probeRange"), [stats.lo, stats.hi]);
|
|
1996
|
-
setUniform(gl, lensLoc("u_probeSlope"), [stats.slopeX, stats.slopeY]);
|
|
1997
|
-
setUniform(gl, lensLoc("u_probe"), [stats.r, stats.g, stats.b]);
|
|
2010
|
+
return gpuTimer.time(() => {
|
|
2011
|
+
if (options.backdrop) {
|
|
2012
|
+
const fbo = ensureBackdropFbo();
|
|
2013
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
|
2014
|
+
gl.viewport(0, 0, width, height);
|
|
2015
|
+
options.backdrop(gl, { framebuffer: fbo, width, height });
|
|
2016
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
2017
|
+
gl.viewport(0, 0, width, height);
|
|
2018
|
+
gl.disable(gl.BLEND);
|
|
2019
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
2020
|
+
gl.disable(gl.DEPTH_TEST);
|
|
2021
|
+
gl.disable(gl.CULL_FACE);
|
|
2022
|
+
gl.disable(gl.STENCIL_TEST);
|
|
2023
|
+
gl.colorMask(true, true, true, true);
|
|
2024
|
+
gl.depthMask(true);
|
|
2025
|
+
gl.bindVertexArray(null);
|
|
2026
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
2027
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
2028
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
2029
|
+
gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL);
|
|
1998
2030
|
} else {
|
|
1999
|
-
|
|
2031
|
+
ctx.clearRect(0, 0, width, height);
|
|
2032
|
+
options.scene?.(ctx, width, height, options.offsetX ?? 0, options.offsetY ?? 0, options.density);
|
|
2033
|
+
gl.bindTexture(gl.TEXTURE_2D, contentTexture);
|
|
2034
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, sceneCanvas);
|
|
2035
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2000
2036
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
gl.
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
morph2: piece.morph2,
|
|
2018
|
-
bodyInLens: true,
|
|
2019
|
-
touch: piece.touch,
|
|
2020
|
-
progress: piece.progress,
|
|
2021
|
-
// The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives
|
|
2022
|
-
// in the core: while it lived here, Android didn't have it at all.
|
|
2023
|
-
shadow: stats ? shadowOpacity(stats.busy) : 1,
|
|
2024
|
-
// The probe has already computed the ambient color — the shadow gets it for free. Taken
|
|
2025
|
-
// as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the
|
|
2026
|
-
// steps the smoothing was written to remove.
|
|
2027
|
-
ambient: stats ? [stats.r, stats.g, stats.b] : void 0,
|
|
2028
|
-
appear: piece.appear,
|
|
2029
|
-
lift: piece.lift
|
|
2030
|
-
});
|
|
2031
|
-
applyObject(gl, surfaceLoc, {
|
|
2032
|
-
...toDeviceSurfaceUniforms(rawSurface, options.density),
|
|
2033
|
-
u_center: [piece.centerX, piece.centerY]
|
|
2034
|
-
});
|
|
2035
|
-
setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);
|
|
2036
|
-
setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);
|
|
2037
|
-
const hasIcon = Boolean(piece.icon && options.iconMask);
|
|
2038
|
-
setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);
|
|
2039
|
-
setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);
|
|
2040
|
-
setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);
|
|
2041
|
-
setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);
|
|
2042
|
-
bindTextureAt(gl, 1, iconTexture, surfaceProgram, "u_icon");
|
|
2043
|
-
setUniform(gl, surfaceLoc("u_iconSize"), hasIcon ? [width, height] : [1, 1]);
|
|
2044
|
-
const hasColor = Boolean(piece.overlay && options.colorLayer);
|
|
2045
|
-
setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);
|
|
2046
|
-
bindTextureAt(gl, 2, colorTexture, surfaceProgram, "u_overlay");
|
|
2047
|
-
setUniform(gl, surfaceLoc("u_overlaySize"), hasColor ? [width, height] : [1, 1]);
|
|
2048
|
-
setUniform(gl, surfaceLoc("u_resolution"), [width, height]);
|
|
2037
|
+
if (options.colorLayer) {
|
|
2038
|
+
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
2039
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.colorLayer);
|
|
2040
|
+
}
|
|
2041
|
+
if (options.iconMask) {
|
|
2042
|
+
gl.bindTexture(gl.TEXTURE_2D, iconTexture);
|
|
2043
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, options.iconMask);
|
|
2044
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
2045
|
+
}
|
|
2046
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
2047
|
+
gl.viewport(0, 0, width, height);
|
|
2048
|
+
gl.disable(gl.BLEND);
|
|
2049
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
2050
|
+
gl.useProgram(blitProgram);
|
|
2051
|
+
bindTextureAt(gl, 0, contentTexture, blitProgram, "u_content");
|
|
2052
|
+
setUniform(gl, blitLoc("u_resolution"), [width, height]);
|
|
2049
2053
|
drawFullscreenTriangle(gl);
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2054
|
+
const probes = [];
|
|
2055
|
+
for (let index = 0; index < options.pieces.length; index += 1) {
|
|
2056
|
+
const piece = options.pieces[index];
|
|
2057
|
+
const halfWidth = piece.geometry.width * options.density / 2;
|
|
2058
|
+
const halfHeight = piece.geometry.height * options.density / 2;
|
|
2059
|
+
const rect = {
|
|
2060
|
+
centerX: piece.centerX,
|
|
2061
|
+
centerY: piece.centerY,
|
|
2062
|
+
halfWidth,
|
|
2063
|
+
halfHeight
|
|
2064
|
+
};
|
|
2065
|
+
const fresh = index === 0 ? probe.sample(contentTexture, width, height, rect) : probe.statsFor(width, height, rect);
|
|
2066
|
+
const stats = fresh ? settleStats(index, fresh) : null;
|
|
2067
|
+
probes.push(stats);
|
|
2068
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
2069
|
+
gl.viewport(0, 0, width, height);
|
|
2070
|
+
gl.enable(gl.BLEND);
|
|
2071
|
+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
2072
|
+
const reachOf = (m) => m ? Math.hypot(m.offsetX, m.offsetY) + Math.max(m.width, m.height) / 2 + m.smoothing : 0;
|
|
2073
|
+
const morphReach = Math.max(reachOf(piece.morph), reachOf(piece.morph2));
|
|
2074
|
+
const touchReach = piece.touch ? Math.hypot(piece.touch.pullX, piece.touch.pullY) + piece.touch.waveAmp * 2 + Math.max(piece.geometry.width, piece.geometry.height) * 0.05 * piece.touch.press : 0;
|
|
2075
|
+
const padPx = (lensPadDp(piece.geometry, piece.optics) + surfacePadDp(piece.geometry, 0) + morphReach + touchReach) * options.density;
|
|
2076
|
+
const left = Math.max(0, Math.floor(piece.centerX - halfWidth - padPx));
|
|
2077
|
+
const right = Math.min(width, Math.ceil(piece.centerX + halfWidth + padPx));
|
|
2078
|
+
const top = Math.max(0, Math.floor(height - (piece.centerY + halfHeight + padPx)));
|
|
2079
|
+
const bottom = Math.min(height, Math.ceil(height - (piece.centerY - halfHeight - padPx)));
|
|
2080
|
+
gl.enable(gl.SCISSOR_TEST);
|
|
2081
|
+
gl.scissor(left, top, Math.max(0, right - left), Math.max(0, bottom - top));
|
|
2082
|
+
gl.useProgram(lensProgram);
|
|
2083
|
+
bindTextureAt(gl, 0, contentTexture, lensProgram, "content");
|
|
2084
|
+
setUniform(gl, lensLoc("u_contentSize"), [width, height]);
|
|
2085
|
+
setUniform(gl, lensLoc("u_resolution"), [width, height]);
|
|
2086
|
+
setUniform(gl, lensLoc("u_center"), [piece.centerX, piece.centerY]);
|
|
2087
|
+
setUniform(gl, lensLoc("u_reach"), Math.max(width, height));
|
|
2088
|
+
setUniform(gl, lensLoc("u_contentMin"), [1, 1]);
|
|
2089
|
+
setUniform(gl, lensLoc("u_contentMax"), [width - 1, height - 1]);
|
|
2090
|
+
if (stats) {
|
|
2091
|
+
setUniform(gl, lensLoc("u_probeLuma"), stats.luma);
|
|
2092
|
+
setUniform(gl, lensLoc("u_probeBusy"), stats.busy);
|
|
2093
|
+
setUniform(gl, lensLoc("u_probeRange"), [stats.lo, stats.hi]);
|
|
2094
|
+
setUniform(gl, lensLoc("u_probeSlope"), [stats.slopeX, stats.slopeY]);
|
|
2095
|
+
setUniform(gl, lensLoc("u_probe"), [stats.r, stats.g, stats.b]);
|
|
2096
|
+
} else {
|
|
2097
|
+
setUniform(gl, lensLoc("u_probeLuma"), -1);
|
|
2098
|
+
}
|
|
2099
|
+
const lens = toLensProps(piece.optics, piece.geometry, options.density, {
|
|
2100
|
+
debug: options.debug,
|
|
2101
|
+
morph: piece.morph,
|
|
2102
|
+
morph2: piece.morph2,
|
|
2103
|
+
touch: piece.touch,
|
|
2104
|
+
progress: piece.progress,
|
|
2105
|
+
light: piece.light,
|
|
2106
|
+
appear: piece.appear,
|
|
2107
|
+
accent: piece.accent
|
|
2108
|
+
});
|
|
2109
|
+
applyChannel(gl, lensLoc, lens.uniformNames, lens.uniformSizes, lens.uniformValues);
|
|
2110
|
+
drawFullscreenTriangle(gl);
|
|
2111
|
+
gl.useProgram(surfaceProgram);
|
|
2112
|
+
const rawSurface = toSurfaceUniforms(piece.optics, piece.geometry, {
|
|
2113
|
+
debug: options.debug,
|
|
2114
|
+
morph: piece.morph,
|
|
2115
|
+
morph2: piece.morph2,
|
|
2116
|
+
bodyInLens: true,
|
|
2117
|
+
touch: piece.touch,
|
|
2118
|
+
progress: piece.progress,
|
|
2119
|
+
// The shadow is denser over text, weaker over a flat backdrop (M 11:47). The rule lives
|
|
2120
|
+
// in the core: while it lived here, Android didn't have it at all.
|
|
2121
|
+
shadow: stats ? shadowOpacity(stats.busy) : 1,
|
|
2122
|
+
// The probe has already computed the ambient color — the shadow gets it for free. Taken
|
|
2123
|
+
// as-is: `settleStats` has already smoothed it, and rounding would bring back exactly the
|
|
2124
|
+
// steps the smoothing was written to remove.
|
|
2125
|
+
ambient: stats ? [stats.r, stats.g, stats.b] : void 0,
|
|
2126
|
+
appear: piece.appear,
|
|
2127
|
+
lift: piece.lift
|
|
2128
|
+
});
|
|
2129
|
+
applyObject(gl, surfaceLoc, {
|
|
2130
|
+
...toDeviceSurfaceUniforms(rawSurface, options.density),
|
|
2131
|
+
u_center: [piece.centerX, piece.centerY]
|
|
2132
|
+
});
|
|
2133
|
+
setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[0]), piece.press ?? 0);
|
|
2134
|
+
setUniform(gl, surfaceLoc(DYNAMIC_UNIFORMS[1]), piece.active ?? 0);
|
|
2135
|
+
const hasIcon = Boolean(piece.icon && options.iconMask);
|
|
2136
|
+
setUniform(gl, surfaceLoc(ICON_UNIFORMS[0]), hasIcon ? 1 : 0);
|
|
2137
|
+
setUniform(gl, surfaceLoc(ICON_UNIFORMS[1]), 1);
|
|
2138
|
+
setUniform(gl, surfaceLoc(ICON_UNIFORMS[2]), piece.inkIdle ?? [1, 1, 1, 1]);
|
|
2139
|
+
setUniform(gl, surfaceLoc(ICON_UNIFORMS[3]), piece.inkActive ?? [1, 1, 1, 1]);
|
|
2140
|
+
bindTextureAt(gl, 1, iconTexture, surfaceProgram, "u_icon");
|
|
2141
|
+
setUniform(gl, surfaceLoc("u_iconSize"), hasIcon ? [width, height] : [1, 1]);
|
|
2142
|
+
const hasColor = Boolean(piece.overlay && options.colorLayer);
|
|
2143
|
+
setUniform(gl, surfaceLoc(OVERLAY_UNIFORMS[0]), hasColor ? 1 : 0);
|
|
2144
|
+
bindTextureAt(gl, 2, colorTexture, surfaceProgram, "u_overlay");
|
|
2145
|
+
setUniform(gl, surfaceLoc("u_overlaySize"), hasColor ? [width, height] : [1, 1]);
|
|
2146
|
+
setUniform(gl, surfaceLoc("u_resolution"), [width, height]);
|
|
2147
|
+
drawFullscreenTriangle(gl);
|
|
2148
|
+
}
|
|
2149
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
2150
|
+
return { probes };
|
|
2151
|
+
});
|
|
2053
2152
|
}
|
|
2054
2153
|
function destroy() {
|
|
2055
2154
|
probe.destroy();
|
|
@@ -2059,13 +2158,24 @@ function createVireGlassRenderer(canvas) {
|
|
|
2059
2158
|
gl.deleteTexture(contentTexture);
|
|
2060
2159
|
gl.deleteTexture(iconTexture);
|
|
2061
2160
|
gl.deleteTexture(colorTexture);
|
|
2161
|
+
if (backdropFbo) gl.deleteFramebuffer(backdropFbo);
|
|
2162
|
+
gpuTimer.destroy();
|
|
2062
2163
|
}
|
|
2063
|
-
return { resize, render, destroy };
|
|
2164
|
+
return { resize, render, getLastGpuMs: gpuTimer.getLastMs, destroy };
|
|
2064
2165
|
}
|
|
2065
2166
|
|
|
2167
|
+
exports.FULLSCREEN_TRIANGLE_VERTEX_SOURCE = FULLSCREEN_TRIANGLE_VERTEX_SOURCE;
|
|
2066
2168
|
exports.PROBE_GRID_HEIGHT = PROBE_GRID_HEIGHT;
|
|
2067
2169
|
exports.PROBE_GRID_WIDTH = PROBE_GRID_WIDTH;
|
|
2170
|
+
exports.bindTextureAt = bindTextureAt;
|
|
2171
|
+
exports.compileShader = compileShader;
|
|
2172
|
+
exports.createFramebuffer = createFramebuffer;
|
|
2068
2173
|
exports.createProbe = createProbe;
|
|
2174
|
+
exports.createProgram = createProgram;
|
|
2175
|
+
exports.createTexture = createTexture;
|
|
2069
2176
|
exports.createVireGlassRenderer = createVireGlassRenderer;
|
|
2177
|
+
exports.drawFullscreenTriangle = drawFullscreenTriangle;
|
|
2178
|
+
exports.locationCache = locationCache;
|
|
2179
|
+
exports.setUniform = setUniform;
|
|
2070
2180
|
//# sourceMappingURL=index.cjs.map
|
|
2071
2181
|
//# sourceMappingURL=index.cjs.map
|