diff --git a/app.js b/app.js index 1436ab9..c8cfb25 100644 --- a/app.js +++ b/app.js @@ -149,12 +149,25 @@ uniform float iTime; uniform float iTimeDelta; uniform int iFrame; uniform vec4 iMouse; +uniform vec4 iDate; ${userCode} void main() { mainImage(outColor, gl_FragCoord.xy); }`; } +function setIDateUniform(gl, loc) { + if (loc == null) return; + const d = new Date(); + gl.uniform4f( + loc, + d.getFullYear(), + d.getMonth() + 1, + d.getDate(), + d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + d.getMilliseconds() * 0.001 + ); +} + function createQuad(gl) { const quad = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]); const vao = gl.createVertexArray(); @@ -169,20 +182,30 @@ function createQuad(gl) { } function compileProgram(gl, fragmentShaderSource) { - function compile(type, source) { + function compile(type, label, source) { + if (gl.isContextLost?.()) { + throw new Error(`${label}: WebGL context lost`); + } const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const info = gl.getShaderInfoLog(shader); + let info = (gl.getShaderInfoLog(shader) || "").trim(); + if (!info) { + const err = gl.getError(); + info = + err && err !== gl.NO_ERROR + ? `WebGL getError 0x${err.toString(16)} (driver returned no compile log)` + : "No compile log (often: shader too complex, loop/unroll limits, or driver bug)."; + } gl.deleteShader(shader); - throw new Error(info || "unknown compile error"); + throw new Error(`${label} shader:\n${info}`); } return shader; } - const vs = compile(gl.VERTEX_SHADER, vertexShaderSource); - const fs = compile(gl.FRAGMENT_SHADER, fragmentShaderSource); + const vs = compile(gl.VERTEX_SHADER, "Vertex", vertexShaderSource); + const fs = compile(gl.FRAGMENT_SHADER, "Fragment", fragmentShaderSource); const program = gl.createProgram(); gl.attachShader(program, vs); gl.attachShader(program, fs); @@ -190,9 +213,16 @@ function compileProgram(gl, fragmentShaderSource) { gl.deleteShader(vs); gl.deleteShader(fs); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - const info = gl.getProgramInfoLog(program); + let info = (gl.getProgramInfoLog(program) || "").trim(); + if (!info) { + const err = gl.getError(); + info = + err && err !== gl.NO_ERROR + ? `WebGL getError 0x${err.toString(16)} (no link log)` + : "No link log (vertex/fragment interface mismatch or resource limits)."; + } gl.deleteProgram(program); - throw new Error(info || "unknown link error"); + throw new Error(`Program link:\n${info}`); } return program; } @@ -260,6 +290,7 @@ function createPreviewCard(name, code) { iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"), iFrame: gl.getUniformLocation(program, "iFrame"), iMouse: gl.getUniformLocation(program, "iMouse"), + iDate: gl.getUniformLocation(program, "iDate"), }; const state = { @@ -366,6 +397,7 @@ function openDetail(previewState) { iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"), iFrame: gl.getUniformLocation(program, "iFrame"), iMouse: gl.getUniformLocation(program, "iMouse"), + iDate: gl.getUniformLocation(program, "iDate"), }; detailRuntime = { @@ -424,6 +456,7 @@ function renderAll(ts) { gl.uniform1f(uniforms.iTime, preview.localTime); gl.uniform1f(uniforms.iTimeDelta, preview.isPlaying && !paused ? localDt : 0); gl.uniform1i(uniforms.iFrame, preview.localFrame); + setIDateUniform(gl, uniforms.iDate); gl.uniform4f( uniforms.iMouse, mouse.x, @@ -452,6 +485,7 @@ function renderAll(ts) { gl.uniform1f(uniforms.iTime, elapsed); gl.uniform1f(uniforms.iTimeDelta, dt); gl.uniform1i(uniforms.iFrame, frame); + setIDateUniform(gl, uniforms.iDate); gl.uniform4f( uniforms.iMouse, mouse.x, diff --git a/display.js b/display.js index e25758a..f71b6fe 100644 --- a/display.js +++ b/display.js @@ -106,6 +106,7 @@ uniform float iTime; uniform float iTimeDelta; uniform int iFrame; uniform vec4 iMouse; +uniform vec4 iDate; uniform sampler2D iChannel0; uniform sampler2D iChannel1; uniform sampler2D iChannel2; @@ -114,6 +115,18 @@ ${userCode} void main() { mainImage(outColor, gl_FragCoord.xy); }`; } +function setIDateUniform(gl, loc) { + if (loc == null) return; + const d = new Date(); + gl.uniform4f( + loc, + d.getFullYear(), + d.getMonth() + 1, + d.getDate(), + d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds() + d.getMilliseconds() * 0.001 + ); +} + function createQuad(gl) { const quad = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]); const vao = gl.createVertexArray(); @@ -128,19 +141,29 @@ function createQuad(gl) { } function compileProgram(gl, fragmentShaderSource) { - function compile(type, source) { + function compile(type, label, source) { + if (gl.isContextLost?.()) { + throw new Error(`${label}: WebGL context lost`); + } const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { - const info = gl.getShaderInfoLog(shader); + let info = (gl.getShaderInfoLog(shader) || "").trim(); + if (!info) { + const err = gl.getError(); + info = + err && err !== gl.NO_ERROR + ? `WebGL getError 0x${err.toString(16)} (driver returned no compile log)` + : "No compile log (often: shader too complex, loop/unroll limits, or driver bug). Try a simpler shader."; + } gl.deleteShader(shader); - throw new Error(info || "unknown compile error"); + throw new Error(`${label} shader:\n${info}`); } return shader; } - const vs = compile(gl.VERTEX_SHADER, vertexShaderSource); - const fs = compile(gl.FRAGMENT_SHADER, fragmentShaderSource); + const vs = compile(gl.VERTEX_SHADER, "Vertex", vertexShaderSource); + const fs = compile(gl.FRAGMENT_SHADER, "Fragment", fragmentShaderSource); const program = gl.createProgram(); gl.attachShader(program, vs); gl.attachShader(program, fs); @@ -148,9 +171,16 @@ function compileProgram(gl, fragmentShaderSource) { gl.deleteShader(vs); gl.deleteShader(fs); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - const info = gl.getProgramInfoLog(program); + let info = (gl.getProgramInfoLog(program) || "").trim(); + if (!info) { + const err = gl.getError(); + info = + err && err !== gl.NO_ERROR + ? `WebGL getError 0x${err.toString(16)} (no link log)` + : "No link log (vertex/fragment interface mismatch or resource limits)."; + } gl.deleteProgram(program); - throw new Error(info || "unknown link error"); + throw new Error(`Program link:\n${info}`); } return program; } @@ -349,6 +379,7 @@ function ensurePreviewWebGL(state) { iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"), iFrame: gl.getUniformLocation(program, "iFrame"), iMouse: gl.getUniformLocation(program, "iMouse"), + iDate: gl.getUniformLocation(program, "iDate"), }; state.gl = gl; state.program = program; @@ -611,6 +642,7 @@ function openDetail(previewState) { iTimeDelta: gl.getUniformLocation(program, "iTimeDelta"), iFrame: gl.getUniformLocation(program, "iFrame"), iMouse: gl.getUniformLocation(program, "iMouse"), + iDate: gl.getUniformLocation(program, "iDate"), }, mouse: { x: 0, y: 0, downX: 0, downY: 0, down: false }, _layoutW: 0, @@ -741,6 +773,7 @@ function renderAll(ts) { gl.uniform1f(uniforms.iTimeDelta, 0); gl.uniform1i(uniforms.iFrame, 0); } + setIDateUniform(gl, uniforms.iDate); gl.uniform4f( uniforms.iMouse, mouse.x, @@ -776,6 +809,7 @@ function renderAll(ts) { gl.uniform1f(uniforms.iTime, elapsed); gl.uniform1f(uniforms.iTimeDelta, dt); gl.uniform1i(uniforms.iFrame, frame); + setIDateUniform(gl, uniforms.iDate); gl.uniform4f( uniforms.iMouse, mouse.x,