Mirror: A frag-canvas custom element to apply Shadertoy fragment shaders to a canvas or image/video element
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Add vague Shadertoy preprocessing (#1)

* Add preprocessing for input shaders

* Add changeset

authored by

Phil Pluckthun and committed by
GitHub
98b43994 9a791a85

+52 -6
+5
.changeset/angry-dogs-win.md
··· 1 + --- 2 + 'frag-canvas': patch 3 + --- 4 + 5 + Add preprocessing matching Shadertoy input API vaguely
+47 -6
src/frag-canvas-element.ts
··· 1 + const VERSION_300 = '#version 300 es'; 2 + 1 3 const VS_SOURCE_100 = 2 4 'attribute vec2 vPos;\n' + 3 5 'void main() {\n' + 4 6 ' gl_Position = vec4(vPos, 0.0, 1.0);\n' + 5 7 '}'; 6 8 const VS_SOURCE_300 = 7 - '#version 300 es\n' + 9 + `${VERSION_300}\n` + 8 10 'in vec4 vPos;\n' + 9 11 'void main() {\n' + 10 12 ' gl_Position = vPos;\n' + ··· 21 23 DATE.getSeconds() + 22 24 DATE.getMilliseconds() * 0.001; 23 25 return [year, month, day, time] as const; 26 + }; 27 + 28 + const preprocessShader = (source: string, isES300: boolean) => { 29 + let header = ''; 30 + let output = source; 31 + 32 + if (output.startsWith(VERSION_300)) { 33 + output = output.slice(VERSION_300.length + 1); 34 + header += `${VERSION_300}\n`; 35 + } 36 + 37 + if (!/^\s*precision /.test(output)) header += 'precision highp float;\n'; 38 + 39 + if (output.includes('iChannel0')) header += 'uniform sampler2D iChannel0;\n'; 40 + if (output.includes('iResolution')) header += 'uniform vec2 iResolution;\n'; 41 + if (output.includes('iChannelResolution')) 42 + header += 'uniform vec3 iChannelResolution[1];\n'; 43 + if (output.includes('iTime')) header += 'uniform float iTime;\n'; 44 + if (output.includes('iTimeDelta')) header += 'uniform float iTimeDelta;\n'; 45 + if (output.includes('iFrame')) header += 'uniform float iFrame;\n'; 46 + if (output.includes('iChannel')) header += 'uniform float iChannel;\n'; 47 + if (output.includes('iDate')) header += 'uniform vec4 iDate;\n'; 48 + 49 + if (isES300 && output.includes('gl_FragColor')) 50 + header += 'out vec4 gl_FragColor;\n'; 51 + if (isES300 && output.includes('gl_FragCoord')) 52 + header += 'in vec2 gl_FragCoord;\n'; 53 + 54 + if (!/main\s*\(/.test(output)) { 55 + const ioRe = /\(\s*out\s+vec4\s+(\S+)\s*,\s*in\s+vec2\s+(\S+)\s*\)/g; 56 + const io = ioRe.exec(source); 57 + output = output.replace(/mainImage\s*\(/, 'main(').replace(ioRe, '()'); 58 + if (io && io[1] !== 'gl_FragColor') 59 + header += `#define ${io[1]} gl_FragColor\n`; 60 + if (io && io[2] !== 'gl_FragCoord') 61 + header += `#define ${io[2]} gl_FragCoord.xy\n`; 62 + } 63 + 64 + if (!isES300) output = output.replace(/texture\s+\(/g, 'texture2D('); 65 + 66 + return `${header}\n${output}`; 24 67 }; 25 68 26 69 interface InitState { ··· 116 159 117 160 updateFragShader(fragSource: string) { 118 161 fragSource = fragSource.trim(); 119 - gl.shaderSource(fragShader, fragSource); 162 + const isES300 = /\s+#version 300/i.test(fragSource); 163 + gl.shaderSource(fragShader, preprocessShader(fragSource, isES300)); 120 164 gl.compileShader(fragShader); 121 - 122 - const vertShader = /\s+#version 300/i.test(fragSource) 123 - ? vertShader300 124 - : vertShader100; 165 + const vertShader = isES300 ? vertShader300 : vertShader100; 125 166 gl.attachShader(program, vertShader); 126 167 gl.attachShader(program, fragShader); 127 168