mirror of
https://github.com/EndPwnArchive/bspwn-lambda.git
synced 2024-08-14 23:57:04 +00:00
444 lines
No EOL
12 KiB
JavaScript
444 lines
No EOL
12 KiB
JavaScript
/* https://github.com/mrdoob/glsl-sandbox */
|
|
|
|
if (!window.requestAnimationFrame) {
|
|
|
|
window.requestAnimationFrame = (function () {
|
|
|
|
return window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
window.oRequestAnimationFrame ||
|
|
window.msRequestAnimationFrame ||
|
|
function (callback, element) {
|
|
|
|
window.setTimeout(callback, 1000 / 60);
|
|
|
|
};
|
|
|
|
})();
|
|
|
|
}
|
|
|
|
// Get older browsers safely through init code, so users can read the
|
|
// message about how to download newer browsers.
|
|
if (!Date.now) {
|
|
Date.now = function () {
|
|
return +new Date();
|
|
};
|
|
}
|
|
|
|
var quality = 1, quality_levels = [0.5, 1, 2, 4, 8];
|
|
var toolbar, compileButton, fullscreenButton, compileTimer, errorLines = [];
|
|
var canvas, gl, buffer, currentProgram, vertexPosition, screenVertexPosition,
|
|
parameters = { startTime: Date.now(), time: 0, mouseX: 0.5, mouseY: 0.5, screenWidth: 0, screenHeight: 0 },
|
|
surface = { centerX: 0, centerY: 0, width: 1, height: 1, isPanning: false, isZooming: false, lastX: 0, lastY: 0 },
|
|
frontTarget, backTarget, screenProgram, getWebGL, resizer = {}, compileOnChangeCode = true;
|
|
|
|
function init() {
|
|
|
|
console.log('initializing...');
|
|
|
|
if (!document.addEventListener) {
|
|
return;
|
|
}
|
|
|
|
canvas = document.createElement('canvas');
|
|
document.body.appendChild(canvas);
|
|
|
|
// Initialise WebGL
|
|
|
|
try {
|
|
|
|
gl = canvas.getContext('experimental-webgl', { preserveDrawingBuffer: true });
|
|
|
|
} catch (error) { }
|
|
|
|
if (gl) {
|
|
|
|
// enable dFdx, dFdy, fwidth
|
|
gl.getExtension('OES_standard_derivatives');
|
|
|
|
// Create vertex buffer (2 triangles)
|
|
|
|
buffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([- 1.0, - 1.0, 1.0, - 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0, 1.0, - 1.0, 1.0]), gl.STATIC_DRAW);
|
|
|
|
// Create surface buffer (coordinates at screen corners)
|
|
|
|
surface.buffer = gl.createBuffer();
|
|
}
|
|
|
|
var clientXLast, clientYLast;
|
|
|
|
document.addEventListener('mousemove', function (event) {
|
|
|
|
var clientX = event.clientX;
|
|
var clientY = event.clientY;
|
|
|
|
if (clientXLast == clientX && clientYLast == clientY)
|
|
return;
|
|
|
|
clientXLast = clientX;
|
|
clientYLast = clientY;
|
|
|
|
parameters.mouseX = clientX / window.innerWidth;
|
|
parameters.mouseY = 1 - clientY / window.innerHeight;
|
|
|
|
}, false);
|
|
|
|
onWindowResize();
|
|
window.addEventListener('resize', onWindowResize, false);
|
|
|
|
compile();
|
|
compileScreenProgram();
|
|
|
|
}
|
|
|
|
function computeSurfaceCorners() {
|
|
|
|
if (gl) {
|
|
|
|
surface.width = surface.height * parameters.screenWidth / parameters.screenHeight;
|
|
|
|
var halfWidth = surface.width * 0.5, halfHeight = surface.height * 0.5;
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, surface.buffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
surface.centerX - halfWidth, surface.centerY - halfHeight,
|
|
surface.centerX + halfWidth, surface.centerY - halfHeight,
|
|
surface.centerX - halfWidth, surface.centerY + halfHeight,
|
|
surface.centerX + halfWidth, surface.centerY - halfHeight,
|
|
surface.centerX + halfWidth, surface.centerY + halfHeight,
|
|
surface.centerX - halfWidth, surface.centerY + halfHeight]), gl.STATIC_DRAW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function resetSurface() {
|
|
|
|
surface.centerX = surface.centerY = 0;
|
|
surface.height = 1;
|
|
computeSurfaceCorners();
|
|
|
|
}
|
|
|
|
function compile() {
|
|
|
|
console.log('compiling shader...');
|
|
|
|
if (!gl) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var program = gl.createProgram();
|
|
var fragment = document.getElementById('shaderCode').textContent;
|
|
var vertex = document.getElementById('surfaceVertexShader').textContent;
|
|
|
|
var vs = createShader(vertex, gl.VERTEX_SHADER);
|
|
var fs = createShader(fragment, gl.FRAGMENT_SHADER);
|
|
|
|
if (vs == null || fs == null) return null;
|
|
|
|
gl.attachShader(program, vs);
|
|
gl.attachShader(program, fs);
|
|
|
|
gl.deleteShader(vs);
|
|
gl.deleteShader(fs);
|
|
|
|
gl.linkProgram(program);
|
|
|
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
|
|
var error = gl.getProgramInfoLog(program);
|
|
|
|
compileButton.title = error;
|
|
console.error(error);
|
|
|
|
console.error('VALIDATE_STATUS: ' + gl.getProgramParameter(program, gl.VALIDATE_STATUS), 'ERROR: ' + gl.getError());
|
|
compileButton.style.color = '#ff0000';
|
|
compileButton.textContent = 'compiled with errors';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (currentProgram) {
|
|
|
|
gl.deleteProgram(currentProgram);
|
|
|
|
}
|
|
|
|
currentProgram = program;
|
|
|
|
// Cache uniforms
|
|
|
|
cacheUniformLocation(program, 'time');
|
|
cacheUniformLocation(program, 'mouse');
|
|
cacheUniformLocation(program, 'resolution');
|
|
cacheUniformLocation(program, 'backbuffer');
|
|
cacheUniformLocation(program, 'surfaceSize');
|
|
|
|
// Load program into GPU
|
|
|
|
gl.useProgram(currentProgram);
|
|
|
|
// Set up buffers
|
|
|
|
surface.positionAttribute = gl.getAttribLocation(currentProgram, "surfacePosAttrib");
|
|
gl.enableVertexAttribArray(surface.positionAttribute);
|
|
|
|
vertexPosition = gl.getAttribLocation(currentProgram, "position");
|
|
gl.enableVertexAttribArray(vertexPosition);
|
|
|
|
console.log('compilation finished');
|
|
|
|
}
|
|
|
|
function compileScreenProgram() {
|
|
|
|
console.log('compiling screen program...');
|
|
|
|
if (!gl) { return; }
|
|
|
|
var program = gl.createProgram();
|
|
var fragment = document.getElementById('fragmentShader').textContent;
|
|
var vertex = document.getElementById('vertexShader').textContent;
|
|
|
|
var vs = createShader(vertex, gl.VERTEX_SHADER);
|
|
var fs = createShader(fragment, gl.FRAGMENT_SHADER);
|
|
|
|
gl.attachShader(program, vs);
|
|
gl.attachShader(program, fs);
|
|
|
|
gl.deleteShader(vs);
|
|
gl.deleteShader(fs);
|
|
|
|
gl.linkProgram(program);
|
|
|
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
|
|
console.error('VALIDATE_STATUS: ' + gl.getProgramParameter(program, gl.VALIDATE_STATUS), 'ERROR: ' + gl.getError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
screenProgram = program;
|
|
|
|
gl.useProgram(screenProgram);
|
|
|
|
cacheUniformLocation(program, 'resolution');
|
|
cacheUniformLocation(program, 'texture');
|
|
|
|
screenVertexPosition = gl.getAttribLocation(screenProgram, "position");
|
|
gl.enableVertexAttribArray(screenVertexPosition);
|
|
|
|
console.log('compilation finished');
|
|
|
|
}
|
|
|
|
function cacheUniformLocation(program, label) {
|
|
|
|
if (program.uniformsCache === undefined) {
|
|
|
|
program.uniformsCache = {};
|
|
|
|
}
|
|
|
|
program.uniformsCache[label] = gl.getUniformLocation(program, label);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
function createTarget(width, height) {
|
|
|
|
var target = {};
|
|
|
|
target.framebuffer = gl.createFramebuffer();
|
|
target.renderbuffer = gl.createRenderbuffer();
|
|
target.texture = gl.createTexture();
|
|
|
|
// set up framebuffer
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, target.texture);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
|
|
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_MAG_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, target.framebuffer);
|
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target.texture, 0);
|
|
|
|
// set up renderbuffer
|
|
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, target.renderbuffer);
|
|
|
|
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
|
|
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, target.renderbuffer);
|
|
|
|
// clean up
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
|
|
return target;
|
|
|
|
}
|
|
|
|
function createRenderTargets() {
|
|
|
|
frontTarget = createTarget(parameters.screenWidth, parameters.screenHeight);
|
|
backTarget = createTarget(parameters.screenWidth, parameters.screenHeight);
|
|
|
|
}
|
|
|
|
//
|
|
|
|
var dummyFunction = function () { };
|
|
|
|
|
|
//
|
|
|
|
function htmlEncode(str) {
|
|
|
|
return String(str)
|
|
.replace(/&/g, '&')
|
|
.replace(/"/g, '"')
|
|
.replace(/'/g, ''')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>');
|
|
|
|
}
|
|
|
|
//
|
|
|
|
function createShader(src, type) {
|
|
|
|
var shader = gl.createShader(type);
|
|
var line, lineNum, lineError, index = 0, indexEnd;
|
|
|
|
gl.shaderSource(shader, src);
|
|
gl.compileShader(shader);
|
|
|
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
|
|
var error = gl.getShaderInfoLog(shader);
|
|
|
|
// Remove trailing linefeed, for FireFox's benefit.
|
|
while ((error.length > 1) && (error.charCodeAt(error.length - 1) < 32)) {
|
|
error = error.substring(0, error.length - 1);
|
|
}
|
|
|
|
console.error(error);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
//
|
|
|
|
function onWindowResize(event) {
|
|
|
|
var isMaxWidth = ((resizer.currentWidth === resizer.maxWidth) || (resizer.currentWidth === resizer.minWidth)),
|
|
isMaxHeight = ((resizer.currentHeight === resizer.maxHeight) || (resizer.currentHeight === resizer.minHeight));
|
|
|
|
canvas.width = window.innerWidth / quality;
|
|
canvas.height = window.innerHeight / quality;
|
|
|
|
canvas.style.width = window.innerWidth + 'px';
|
|
canvas.style.height = window.innerHeight + 'px';
|
|
|
|
parameters.screenWidth = canvas.width;
|
|
parameters.screenHeight = canvas.height;
|
|
|
|
computeSurfaceCorners();
|
|
|
|
if (gl) {
|
|
|
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
|
|
createRenderTargets();
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
function animate() {
|
|
|
|
requestAnimationFrame(animate);
|
|
render();
|
|
|
|
}
|
|
|
|
function render() {
|
|
|
|
if (!currentProgram) return;
|
|
|
|
parameters.time = Date.now() - parameters.startTime;
|
|
|
|
// Set uniforms for custom shader
|
|
|
|
gl.useProgram(currentProgram);
|
|
|
|
gl.uniform1f(currentProgram.uniformsCache['time'], parameters.time / 1000);
|
|
gl.uniform2f(currentProgram.uniformsCache['mouse'], parameters.mouseX, parameters.mouseY);
|
|
gl.uniform2f(currentProgram.uniformsCache['resolution'], parameters.screenWidth, parameters.screenHeight);
|
|
gl.uniform1i(currentProgram.uniformsCache['backbuffer'], 0);
|
|
gl.uniform2f(currentProgram.uniformsCache['surfaceSize'], surface.width, surface.height);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, surface.buffer);
|
|
gl.vertexAttribPointer(surface.positionAttribute, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
gl.vertexAttribPointer(vertexPosition, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_2D, backTarget.texture);
|
|
|
|
// Render custom shader to front buffer
|
|
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frontTarget.framebuffer);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
|
|
// Set uniforms for screen shader
|
|
|
|
gl.useProgram(screenProgram);
|
|
|
|
gl.uniform2f(screenProgram.uniformsCache['resolution'], parameters.screenWidth, parameters.screenHeight);
|
|
gl.uniform1i(screenProgram.uniformsCache['texture'], 1);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
gl.vertexAttribPointer(screenVertexPosition, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.activeTexture(gl.TEXTURE1);
|
|
gl.bindTexture(gl.TEXTURE_2D, frontTarget.texture);
|
|
|
|
// Render front buffer to screen
|
|
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
|
|
// Swap buffers
|
|
|
|
var tmp = frontTarget;
|
|
frontTarget = backTarget;
|
|
backTarget = tmp;
|
|
|
|
} |