Update shaders (#73)

* max grid-size from 32 to 256 & support shadertoy-shader format

* max grid-size from 32 to 256 & support shadertoy-shader format

* fix shader loader

* update css-doodle.min

* fix test-case
This commit is contained in:
月影 2022-04-26 18:33:54 +08:00 committed by GitHub
parent 3888b82312
commit 01d0fac7d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 97 additions and 23 deletions

View File

@ -165,7 +165,7 @@
return array[array.length - 1];
}
function scan(source) {
function scan(source, preserveLineBreak = false) {
let iter = iterator$1(String(source).trim());
let tokens = [];
let quoteStack = [];
@ -240,7 +240,7 @@
if (ignoreLeft || ignoreRight) {
continue;
} else {
spaces = ' ';
spaces = preserveLineBreak ? curr : ' ';
}
}
if (tokens.length && (next && next.trim())) {
@ -1200,7 +1200,7 @@
return Tokens;
}
const [ min, max, total ] = [ 1, 32, 32 * 32 ];
const [ min, max, total ] = [ 1, 256, 256 * 256 ];
function parse_grid(size) {
let [x, y, z] = (size + '')
@ -1225,7 +1225,8 @@
}
function parse$7(input) {
let iter = iterator$1(removeParens(scan(input)));
input = input.replace(/\/\/[^\n]*(\n|$)/mg, ''); // remove single-line comment
let iter = iterator$1(removeParens(scan(input, true)));
let stack = [];
let tokens = [];
let identifier;
@ -4303,8 +4304,10 @@
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
}
@ -4326,12 +4329,37 @@
// resolution uniform
let fragment = add_uniform(shaders.fragment || '', 'uniform vec2 u_resolution;');
fragment = add_uniform(fragment, 'uniform float u_time;');
fragment = add_uniform(fragment, 'uniform float u_timeDelta;');
fragment = add_uniform(fragment, 'uniform int u_frameIndex;');
// fragment = add_uniform(fragment, 'uniform vec4 u_mouse;');
// texture uniform
shaders.textures.forEach(n => {
let uniform = `uniform sampler2D ${ n.name };`;
fragment = add_uniform(fragment, uniform);
});
const isShaderToyFragment = /(^|[^\w\_])void\s+mainImage\(\s*out\s+vec4\s+fragColor,\s*in\s+vec2\s+fragCoord\s*\)/mg.test(fragment);
if(isShaderToyFragment) {
fragment = `// https://www.shadertoy.com/howto
#define iResolution vec3(u_resolution, 0)
#define iTime u_time
#define iTimeDelta u_timeDelta
#define iFrame u_frameIndex
${shaders.textures.map((n, i) => `#define iChannel${i} ${n.name}`).join('\n')}
${fragment}
void main() {
mainImage(FragColor, gl_FragCoord.xy);
}`;
}
let program = create_program(
gl,
shaders.vertex || default_vertex_shader,
@ -4367,10 +4395,19 @@
// resolve image data in 72dpi :(
const uTimeLoc = gl.getUniformLocation(program, "u_time");
if(uTimeLoc) {
const uFrameLoc = gl.getUniformLocation(program, "u_frameIndex");
const uTimeDelta = gl.getUniformLocation(program, "u_timeDelta");
if(uTimeLoc || uFrameLoc) {
let frameIndex = 0;
let currentTime = 0;
return Promise.resolve(Cache.set(shaders, (t) => {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform1f(uTimeLoc, t / 1000);
if(uTimeLoc) gl.uniform1f(uTimeLoc, t / 1000);
if(uFrameLoc) gl.uniform1i(uFrameLoc, frameIndex++);
if(uTimeDelta) {
gl.uniform1f(uTimeDelta, (currentTime - t) / 1000);
currentTime = t;
}
gl.drawArrays(gl.TRIANGLES, 0, 6);
return canvas.toDataURL();
}));
@ -5225,7 +5262,7 @@
}
};
requestAnimationFrame(update);
const ret = value();
const ret = value(0);
element.style.backgroundImage = `url(${ret})`;
currentImage = element.style.backgroundImage;
return '';

4
css-doodle.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -49,8 +49,10 @@ function load_texture(gl, image, i) {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
}
@ -72,12 +74,37 @@ function draw_shader(shaders, width, height) {
// resolution uniform
let fragment = add_uniform(shaders.fragment || '', 'uniform vec2 u_resolution;');
fragment = add_uniform(fragment, 'uniform float u_time;');
fragment = add_uniform(fragment, 'uniform float u_timeDelta;');
fragment = add_uniform(fragment, 'uniform int u_frameIndex;');
// fragment = add_uniform(fragment, 'uniform vec4 u_mouse;');
// texture uniform
shaders.textures.forEach(n => {
let uniform = `uniform sampler2D ${ n.name };`;
fragment = add_uniform(fragment, uniform);
});
const isShaderToyFragment = /(^|[^\w\_])void\s+mainImage\(\s*out\s+vec4\s+fragColor,\s*in\s+vec2\s+fragCoord\s*\)/mg.test(fragment);
if(isShaderToyFragment) {
fragment = `// https://www.shadertoy.com/howto
#define iResolution vec3(u_resolution, 0)
#define iTime u_time
#define iTimeDelta u_timeDelta
#define iFrame u_frameIndex
${shaders.textures.map((n, i) => `#define iChannel${i} ${n.name}`).join('\n')}
${fragment}
void main() {
mainImage(FragColor, gl_FragCoord.xy);
}`
}
let program = create_program(
gl,
shaders.vertex || default_vertex_shader,
@ -113,10 +140,19 @@ function draw_shader(shaders, width, height) {
// resolve image data in 72dpi :(
const uTimeLoc = gl.getUniformLocation(program, "u_time");
if(uTimeLoc) {
const uFrameLoc = gl.getUniformLocation(program, "u_frameIndex");
const uTimeDelta = gl.getUniformLocation(program, "u_timeDelta");
if(uTimeLoc || uFrameLoc) {
let frameIndex = 0;
let currentTime = 0;
return Promise.resolve(Cache.set(shaders, (t) => {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform1f(uTimeLoc, t / 1000);
if(uTimeLoc) gl.uniform1f(uTimeLoc, t / 1000);
if(uFrameLoc) gl.uniform1i(uFrameLoc, frameIndex++);
if(uTimeDelta) {
gl.uniform1f(uTimeDelta, (currentTime - t) / 1000);
currentTime = t;
}
gl.drawArrays(gl.TRIANGLES, 0, 6);
return canvas.toDataURL();
}));

View File

@ -247,7 +247,7 @@ if (typeof customElements !== 'undefined') {
}
};
requestAnimationFrame(update);
const ret = value();
const ret = value(0);
element.style.backgroundImage = `url(${ret})`;
currentImage = element.style.backgroundImage;
return '';

View File

@ -1,6 +1,6 @@
import { clamp } from '../utils/index.js';
const [ min, max, total ] = [ 1, 32, 32 * 32 ];
const [ min, max, total ] = [ 1, 256, 256 * 256 ];
export default function parse_grid(size) {
let [x, y, z] = (size + '')

View File

@ -2,7 +2,8 @@ import { scan, iterator, Token } from './tokenizer.js';
import { is_empty } from '../utils/index.js';
function parse(input) {
let iter = iterator(removeParens(scan(input)));
input = input.replace(/\/\/[^\n]*(\n|$)/mg, ''); // remove single-line comment
let iter = iterator(removeParens(scan(input, true)));
let stack = [];
let tokens = [];
let identifier;

View File

@ -158,7 +158,7 @@ function last(array) {
return array[array.length - 1];
}
function scan(source) {
function scan(source, preserveLineBreak = false) {
let iter = iterator(String(source).trim());
let tokens = [];
let quoteStack = [];
@ -233,7 +233,7 @@ function scan(source) {
if (ignoreLeft || ignoreRight) {
continue;
} else {
spaces = ' ';
spaces = preserveLineBreak ? curr : ' ';
}
}
if (tokens.length && (next && next.trim())) {

View File

@ -38,9 +38,9 @@ test('clamp value', t => {
compare(t, '0x1', defaultGrid);
compare(t, '2000,1', { x: 1024, y: 1, z: 1, count: 1024, ratio: 1024 });
compare(t, '70000,1', { x: 65536, y: 1, z: 1, count: 65536, ratio: 65536 });
compare(t, '2000', { x: 32, y: 32, z: 1, count: 1024, ratio: 1 });
compare(t, '70000', { x: 256, y: 256, z: 1, count: 65536, ratio: 1 });
compare(t, '0.5', defaultGrid);

View File

@ -58,7 +58,7 @@ test('should break line on #define ', t => {
void main() {}
`;
let result = {
fragment: '\n#define CONST2\n void main(){}',
fragment: '\n#define CONST2\n\nvoid main(){}',
textures: []
}
compare(t, input, result);