Merge branch 'main' into feat/netcode-rework
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
import noise from "~/assets/shaders/noise.frag?raw"
|
||||
|
||||
import resolveLygia from "~/assets/workers/resolve-lygia.esm"
|
||||
|
||||
let interval: number
|
||||
let timeout: number
|
||||
|
||||
const shaderOptions = { quality: 1, framerate: 1000 / 60 }
|
||||
const screen = { width: 0, height: 0, devicePixelRatio: 0 }
|
||||
|
||||
const _colorStart = [0, 0, 0]
|
||||
const _colorEnd = [0, 0, 0]
|
||||
|
||||
let fragmentShader = resolveLygia(noise);
|
||||
|
||||
let canvas: OffscreenCanvas
|
||||
|
||||
let render: (time: number) => void
|
||||
|
||||
let must_resize = false
|
||||
|
||||
async function main(canvas: OffscreenCanvas) {
|
||||
const gl = canvas.getContext("webgl");
|
||||
if (!gl) {
|
||||
return;
|
||||
}
|
||||
// setup GLSL program
|
||||
const program = gl.createProgram()
|
||||
if (!program) { return }
|
||||
|
||||
const fragment = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
if (!fragment) { return }
|
||||
gl.shaderSource(fragment, fragmentShader)
|
||||
gl.compileShader(fragment);
|
||||
if (!gl.getShaderParameter(fragment, gl.COMPILE_STATUS)) {
|
||||
const lastError = gl.getShaderInfoLog(fragment);
|
||||
console.error(lastError)
|
||||
gl.deleteShader(fragment);
|
||||
return
|
||||
}
|
||||
|
||||
const vertex = gl.createShader(gl.VERTEX_SHADER);
|
||||
if (!vertex) { return }
|
||||
gl.shaderSource(vertex, `attribute vec4 a_position;void main() {gl_Position = a_position;}`)
|
||||
gl.compileShader(vertex);
|
||||
if (!gl.getShaderParameter(vertex, gl.COMPILE_STATUS)) {
|
||||
const lastError = gl.getShaderInfoLog(vertex);
|
||||
console.error(lastError)
|
||||
gl.deleteShader(vertex);
|
||||
return
|
||||
}
|
||||
|
||||
gl.attachShader(program, fragment)
|
||||
gl.attachShader(program, vertex)
|
||||
gl.linkProgram(program)
|
||||
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||
if (!linked) { return }
|
||||
// const program = webglUtils.createProgramFromSources(gl, [vs, fragmentShader2]);
|
||||
|
||||
// look up where the vertex data needs to go.
|
||||
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
|
||||
|
||||
// look up uniform locations
|
||||
const offset = gl.getUniformLocation(program, "u_offset");
|
||||
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
|
||||
const colorStart = gl.getUniformLocation(program, "u_color_start");
|
||||
const quality = gl.getUniformLocation(program, "u_quality");
|
||||
const colorEnd = gl.getUniformLocation(program, "u_color_end");
|
||||
const timeLocation = gl.getUniformLocation(program, "u_time");
|
||||
|
||||
// Create a buffer to put three 2d clip space points in
|
||||
const positionBuffer = gl.createBuffer();
|
||||
|
||||
// Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// fill it with a 2 triangles that cover clipspace
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
||||
-1, -1, // first triangle
|
||||
1, -1,
|
||||
-1, 1,
|
||||
-1, 1, // second triangle
|
||||
1, -1,
|
||||
1, 1,
|
||||
]), gl.STATIC_DRAW);
|
||||
|
||||
|
||||
const gl2 = gl
|
||||
function render(time: number) {
|
||||
if (must_resize) {
|
||||
canvas.width = screen.width * shaderOptions.quality / 10
|
||||
canvas.height = screen.height * shaderOptions.quality / 10
|
||||
must_resize = false;
|
||||
}
|
||||
|
||||
time *= 0.001; // convert to seconds
|
||||
// Tell WebGL how to convert from clip space to pixels
|
||||
gl2.viewport(0, 0, gl2.canvas.width, gl2.canvas.height);
|
||||
|
||||
// Tell it to use our program (pair of shaders)
|
||||
gl2.useProgram(program);
|
||||
|
||||
// Turn on the attribute
|
||||
gl2.enableVertexAttribArray(positionAttributeLocation);
|
||||
|
||||
// Bind the position buffer.
|
||||
gl2.bindBuffer(gl2.ARRAY_BUFFER, positionBuffer);
|
||||
|
||||
// Tell the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
|
||||
gl2.vertexAttribPointer(
|
||||
positionAttributeLocation,
|
||||
2, // 2 components per iteration
|
||||
gl2.FLOAT, // the data is 32bit floats
|
||||
false, // don't normalize the data
|
||||
0, // 0 = move forward size * sizeof(type) each iteration to get the next position
|
||||
0, // start at the beginning of the buffer
|
||||
);
|
||||
|
||||
const secondRatio = screen.width / screen.height
|
||||
|
||||
if (secondRatio < 1) {
|
||||
const half = canvas.height / 2
|
||||
gl2.uniform2f(resolutionLocation, canvas.width, canvas.height * secondRatio);
|
||||
gl2.uniform2f(offset, 0, -half + ((half) / (1 / secondRatio)));
|
||||
} else {
|
||||
const half = canvas.width / 2
|
||||
gl2.uniform2f(resolutionLocation, canvas.width / secondRatio, canvas.height);
|
||||
gl2.uniform2f(offset, -half + ((half) / secondRatio), 0);
|
||||
}
|
||||
gl2.uniform1i(quality, shaderOptions.quality)
|
||||
|
||||
gl2.uniform3f(colorStart, _colorStart[0], _colorStart[1], _colorStart[2]);
|
||||
gl2.uniform3f(colorEnd, _colorEnd[0], _colorEnd[1], _colorEnd[2]);
|
||||
gl2.uniform1f(timeLocation, time);
|
||||
gl2.drawArrays(
|
||||
gl2.TRIANGLES,
|
||||
0, // offset
|
||||
6, // num vertices to process
|
||||
);
|
||||
if (timeout) {
|
||||
self.clearTimeout(timeout)
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(render)
|
||||
|
||||
// self.clearInterval(interval)
|
||||
// interval = self.setInterval(() => requestAnimationFrame(render), 1000 / shaderOptions.framerate)
|
||||
self.clearTimeout(timeout)
|
||||
if (shaderOptions.framerate == 0) {
|
||||
return render
|
||||
}
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
return render
|
||||
}
|
||||
|
||||
self.addEventListener("message", (e) => {
|
||||
const data = e.data
|
||||
if (data.command == "initShader") {
|
||||
canvas = data.canvas
|
||||
shaderOptions.quality = data.shaderOptions.quality
|
||||
shaderOptions.framerate = data.shaderOptions.framerate
|
||||
if (shaderOptions.framerate == 65) {
|
||||
shaderOptions.framerate == Infinity
|
||||
}
|
||||
screen.devicePixelRatio = data.screen.devicePixelRatio
|
||||
screen.width = data.screen.width
|
||||
screen.height = data.screen.height
|
||||
loadShader()
|
||||
} else if (data.command == "killShader") {
|
||||
console.log("killShader")
|
||||
self.clearInterval(interval)
|
||||
self.clearTimeout(timeout)
|
||||
}
|
||||
else if (data.command == "resumeShader") {
|
||||
self.clearInterval(interval)
|
||||
self.clearTimeout(timeout)
|
||||
shaderOptions.framerate = data.shaderOptions.framerate
|
||||
if (shaderOptions.framerate == 65) {
|
||||
shaderOptions.framerate == Infinity
|
||||
}
|
||||
timeout = self.setTimeout(() => {
|
||||
requestAnimationFrame(render)
|
||||
}, 1000 / shaderOptions.framerate)
|
||||
// interval = self.setInterval(() => requestAnimationFrame(render), 1000 / shaderOptions.framerate)
|
||||
} else if (data.command == "recolorShader") {
|
||||
_colorStart[0] = data.colorStart[0]
|
||||
_colorStart[1] = data.colorStart[1]
|
||||
_colorStart[2] = data.colorStart[2]
|
||||
_colorEnd[0] = data.colorEnd[0]
|
||||
_colorEnd[1] = data.colorEnd[1]
|
||||
_colorEnd[2] = data.colorEnd[2]
|
||||
} else if (data.command == "resizeShader") {
|
||||
shaderOptions.quality = data.shaderOptions.quality
|
||||
screen.devicePixelRatio = data.screen.devicePixelRatio
|
||||
screen.width = data.screen.width
|
||||
screen.height = data.screen.height
|
||||
must_resize = true
|
||||
}
|
||||
})
|
||||
|
||||
async function loadShader() {
|
||||
if (!canvas) { return }
|
||||
// let fragmentShader2 = fragmentShader.replace("#define FBM_OCTAVES 6", "#define FBM_OCTAVES " + shaderOptions.quality);
|
||||
const temp = await main(canvas);
|
||||
if (temp) {
|
||||
render = temp
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
function getFile(url) {
|
||||
let httpRequest = new XMLHttpRequest();
|
||||
httpRequest.open("GET", url, false);
|
||||
httpRequest.send();
|
||||
if (httpRequest.status == 200)
|
||||
return httpRequest.responseText;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
function resolveLygia(lines) {
|
||||
if ( !Array.isArray(lines) ) {
|
||||
lines = lines.split(/\r?\n/);
|
||||
}
|
||||
|
||||
let src = "";
|
||||
lines.forEach( (line, i) => {
|
||||
const line_trim = line.trim();
|
||||
if (line_trim.startsWith('#include \"lygia') ) {
|
||||
let include_url = line_trim.substring(15);
|
||||
include_url = "https://lygia.xyz" + include_url.replace(/\"|\;|\s/g,'');
|
||||
src += getFile(include_url) + '\n';
|
||||
}
|
||||
else {
|
||||
src += line + '\n';
|
||||
}
|
||||
});
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
async function resolveLygiaAsync(lines) {
|
||||
if (!Array.isArray(lines))
|
||||
lines = lines.split(/\r?\n/);
|
||||
|
||||
let src = "";
|
||||
const response = await Promise.all(
|
||||
lines.map(async (line, i) => {
|
||||
const line_trim = line.trim();
|
||||
if (line_trim.startsWith('#include "lygia')) {
|
||||
let include_url = line_trim.substring(15);
|
||||
include_url = "https://lygia.xyz" + include_url.replace(/\"|\;|\s/g, "");
|
||||
return fetch(include_url).then((res) => res.text());
|
||||
}
|
||||
else
|
||||
return line;
|
||||
})
|
||||
);
|
||||
|
||||
return response.join("\n");
|
||||
}
|
||||
export { resolveLygia as default };
|
||||
Reference in New Issue
Block a user