refactor(simulation): Higher simulation settings for high-resolution monitors

This commit is contained in:
Timofey Gelazoniya 2021-11-06 11:29:25 +03:00
parent ba5b63f719
commit 25929b73ec
Signed by: zeldon
GPG Key ID: 047886915281DD2A

View File

@ -48,7 +48,7 @@ let config = {
BLOOM: true,
BLOOM_ITERATIONS: 8,
BLOOM_RESOLUTION: 256,
BLOOM_INTENSITY: 0.8,
BLOOM_INTENSITY: 0.3,
BLOOM_THRESHOLD: 0.6,
BLOOM_SOFT_KNEE: 0.7,
SUNRAYS: true,
@ -56,10 +56,8 @@ let config = {
SUNRAYS_WEIGHT: 1.0,
};
class pointerPrototype
{
constructor()
{
class pointerPrototype {
constructor() {
this.id = -1;
this.texcoordX = 0;
this.texcoordY = 0;
@ -79,20 +77,24 @@ pointers.push(new pointerPrototype());
const { gl, ext } = getWebGLContext(canvas);
if (isMobile())
{
if (isMobile()) {
config.DYE_RESOLUTION = 512;
}
if (!ext.supportLinearFiltering)
{
if (window.screen.availHeight >= 1400) {
config.SIM_RESOLUTION = 256;
config.DYE_RESOLUTION = 4096;
config.BLOOM_RESOLUTION = 512;
}
if (!ext.supportLinearFiltering) {
config.DYE_RESOLUTION = 512;
config.SHADING = false;
config.BLOOM = false;
config.SUNRAYS = false;
}
function getWebGLContext(canvas)
{
function getWebGLContext(canvas) {
const params = { alpha: true, depth: false, stencil: false, antialias: false, preserveDrawingBuffer: false };
let gl = canvas.getContext('webgl2', params);
@ -102,12 +104,10 @@ function getWebGLContext(canvas)
let halfFloat;
let supportLinearFiltering;
if (isWebGL2)
{
if (isWebGL2) {
gl.getExtension('EXT_color_buffer_float');
supportLinearFiltering = gl.getExtension('OES_texture_float_linear');
} else
{
} else {
halfFloat = gl.getExtension('OES_texture_half_float');
supportLinearFiltering = gl.getExtension('OES_texture_half_float_linear');
}
@ -119,14 +119,12 @@ function getWebGLContext(canvas)
let formatRG;
let formatR;
if (isWebGL2)
{
if (isWebGL2) {
formatRGBA = getSupportedFormat(gl, gl.RGBA16F, gl.RGBA, halfFloatTexType);
formatRG = getSupportedFormat(gl, gl.RG16F, gl.RG, halfFloatTexType);
formatR = getSupportedFormat(gl, gl.R16F, gl.RED, halfFloatTexType);
}
else
{
else {
formatRGBA = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
formatRG = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
@ -144,12 +142,9 @@ function getWebGLContext(canvas)
};
}
function getSupportedFormat(gl, internalFormat, format, type)
{
if (!supportRenderTextureFormat(gl, internalFormat, format, type))
{
switch (internalFormat)
{
function getSupportedFormat(gl, internalFormat, format, type) {
if (!supportRenderTextureFormat(gl, internalFormat, format, type)) {
switch (internalFormat) {
case gl.R16F:
return getSupportedFormat(gl, gl.RG16F, gl.RG, type);
case gl.RG16F:
@ -165,8 +160,7 @@ function getSupportedFormat(gl, internalFormat, format, type)
};
}
function supportRenderTextureFormat(gl, internalFormat, format, type)
{
function supportRenderTextureFormat(gl, internalFormat, format, type) {
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
@ -183,13 +177,11 @@ function supportRenderTextureFormat(gl, internalFormat, format, type)
return status == gl.FRAMEBUFFER_COMPLETE;
}
function isMobile()
{
function isMobile() {
return /Mobi|Android/i.test(navigator.userAgent);
}
function captureScreenshot()
{
function captureScreenshot() {
let res = getResolution(config.CAPTURE_RESOLUTION);
let target = createFBO(res.width, res.height, ext.formatRGBA.internalFormat, ext.formatRGBA.format, ext.halfFloatTexType, gl.NEAREST);
render(target);
@ -203,8 +195,7 @@ function captureScreenshot()
URL.revokeObjectURL(datauri);
}
function framebufferToTexture(target)
{
function framebufferToTexture(target) {
gl.bindFramebuffer(gl.FRAMEBUFFER, target.fbo);
let length = target.width * target.height * 4;
let texture = new Float32Array(length);
@ -212,14 +203,11 @@ function framebufferToTexture(target)
return texture;
}
function normalizeTexture(texture, width, height)
{
function normalizeTexture(texture, width, height) {
let result = new Uint8Array(texture.length);
let id = 0;
for (let i = height - 1; i >= 0; i--)
{
for (let j = 0; j < width; j++)
{
for (let i = height - 1; i >= 0; i--) {
for (let j = 0; j < width; j++) {
let nid = i * width * 4 + j * 4;
result[nid + 0] = clamp01(texture[id + 0]) * 255;
result[nid + 1] = clamp01(texture[id + 1]) * 255;
@ -231,13 +219,11 @@ function normalizeTexture(texture, width, height)
return result;
}
function clamp01(input)
{
function clamp01(input) {
return Math.min(Math.max(input, 0), 1);
}
function textureToCanvas(texture, width, height)
{
function textureToCanvas(texture, width, height) {
let captureCanvas = document.createElement('canvas');
let ctx = captureCanvas.getContext('2d');
captureCanvas.width = width;
@ -250,10 +236,8 @@ function textureToCanvas(texture, width, height)
return captureCanvas;
}
class Material
{
constructor(vertexShader, fragmentShaderSource)
{
class Material {
constructor(vertexShader, fragmentShaderSource) {
this.vertexShader = vertexShader;
this.fragmentShaderSource = fragmentShaderSource;
this.programs = [];
@ -261,15 +245,13 @@ class Material
this.uniforms = [];
}
setKeywords(keywords)
{
setKeywords(keywords) {
let hash = 0;
for (let i = 0; i < keywords.length; i++)
hash += hashCode(keywords[i]);
let program = this.programs[hash];
if (program == null)
{
if (program == null) {
let fragmentShader = compileShader(gl.FRAGMENT_SHADER, this.fragmentShaderSource, keywords);
program = createProgram(this.vertexShader, fragmentShader);
this.programs[hash] = program;
@ -281,29 +263,24 @@ class Material
this.activeProgram = program;
}
bind()
{
bind() {
gl.useProgram(this.activeProgram);
}
}
class Program
{
constructor(vertexShader, fragmentShader)
{
class Program {
constructor(vertexShader, fragmentShader) {
this.uniforms = {};
this.program = createProgram(vertexShader, fragmentShader);
this.uniforms = getUniforms(this.program);
}
bind()
{
bind() {
gl.useProgram(this.program);
}
}
function createProgram(vertexShader, fragmentShader)
{
function createProgram(vertexShader, fragmentShader) {
let program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
@ -315,20 +292,17 @@ function createProgram(vertexShader, fragmentShader)
return program;
}
function getUniforms(program)
{
function getUniforms(program) {
let uniforms = [];
let uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (let i = 0; i < uniformCount; i++)
{
for (let i = 0; i < uniformCount; i++) {
let uniformName = gl.getActiveUniform(program, i).name;
uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
}
return uniforms;
}
function compileShader(type, source, keywords)
{
function compileShader(type, source, keywords) {
source = addKeywords(source, keywords);
const shader = gl.createShader(type);
@ -341,12 +315,10 @@ function compileShader(type, source, keywords)
return shader;
};
function addKeywords(source, keywords)
{
function addKeywords(source, keywords) {
if (keywords == null) return source;
let keywordsString = '';
keywords.forEach(keyword =>
{
keywords.forEach(keyword => {
keywordsString += '#define ' + keyword + '\n';
});
return keywordsString + source;
@ -827,8 +799,7 @@ const gradientSubtractShader = compileShader(gl.FRAGMENT_SHADER, `
}
`);
const blit = (() =>
{
const blit = (() => {
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
@ -836,20 +807,16 @@ const blit = (() =>
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(0);
return (target, clear = false) =>
{
if (target == null)
{
return (target, clear = false) => {
if (target == null) {
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
else
{
else {
gl.viewport(0, 0, target.width, target.height);
gl.bindFramebuffer(gl.FRAMEBUFFER, target.fbo);
}
if (clear)
{
if (clear) {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
@ -858,8 +825,7 @@ const blit = (() =>
};
})();
function CHECK_FRAMEBUFFER_STATUS()
{
function CHECK_FRAMEBUFFER_STATUS() {
let status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status != gl.FRAMEBUFFER_COMPLETE)
console.trace("Framebuffer error: " + status);
@ -897,8 +863,7 @@ const gradienSubtractProgram = new Program(baseVertexShader, gradientSubtractSha
const displayMaterial = new Material(baseVertexShader, displayShaderSource);
function initFramebuffers()
{
function initFramebuffers() {
let simRes = getResolution(config.SIM_RESOLUTION);
let dyeRes = getResolution(config.DYE_RESOLUTION);
@ -928,8 +893,7 @@ function initFramebuffers()
initSunraysFramebuffers();
}
function initBloomFramebuffers()
{
function initBloomFramebuffers() {
let res = getResolution(config.BLOOM_RESOLUTION);
const texType = ext.halfFloatTexType;
@ -939,8 +903,7 @@ function initBloomFramebuffers()
bloom = createFBO(res.width, res.height, rgba.internalFormat, rgba.format, texType, filtering);
bloomFramebuffers.length = 0;
for (let i = 0; i < config.BLOOM_ITERATIONS; i++)
{
for (let i = 0; i < config.BLOOM_ITERATIONS; i++) {
let width = res.width >> (i + 1);
let height = res.height >> (i + 1);
@ -951,8 +914,7 @@ function initBloomFramebuffers()
}
}
function initSunraysFramebuffers()
{
function initSunraysFramebuffers() {
let res = getResolution(config.SUNRAYS_RESOLUTION);
const texType = ext.halfFloatTexType;
@ -963,8 +925,7 @@ function initSunraysFramebuffers()
sunraysTemp = createFBO(res.width, res.height, r.internalFormat, r.format, texType, filtering);
}
function createFBO(w, h, internalFormat, format, type, param)
{
function createFBO(w, h, internalFormat, format, type, param) {
gl.activeTexture(gl.TEXTURE0);
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
@ -990,8 +951,7 @@ function createFBO(w, h, internalFormat, format, type, param)
height: h,
texelSizeX,
texelSizeY,
attach(id)
{
attach(id) {
gl.activeTexture(gl.TEXTURE0 + id);
gl.bindTexture(gl.TEXTURE_2D, texture);
return id;
@ -999,8 +959,7 @@ function createFBO(w, h, internalFormat, format, type, param)
};
}
function createDoubleFBO(w, h, internalFormat, format, type, param)
{
function createDoubleFBO(w, h, internalFormat, format, type, param) {
let fbo1 = createFBO(w, h, internalFormat, format, type, param);
let fbo2 = createFBO(w, h, internalFormat, format, type, param);
@ -1009,24 +968,19 @@ function createDoubleFBO(w, h, internalFormat, format, type, param)
height: h,
texelSizeX: fbo1.texelSizeX,
texelSizeY: fbo1.texelSizeY,
get read()
{
get read() {
return fbo1;
},
set read(value)
{
set read(value) {
fbo1 = value;
},
get write()
{
get write() {
return fbo2;
},
set write(value)
{
set write(value) {
fbo2 = value;
},
swap()
{
swap() {
let temp = fbo1;
fbo1 = fbo2;
fbo2 = temp;
@ -1034,8 +988,7 @@ function createDoubleFBO(w, h, internalFormat, format, type, param)
};
}
function resizeFBO(target, w, h, internalFormat, format, type, param)
{
function resizeFBO(target, w, h, internalFormat, format, type, param) {
let newFBO = createFBO(w, h, internalFormat, format, type, param);
copyProgram.bind();
gl.uniform1i(copyProgram.uniforms.uTexture, target.attach(0));
@ -1043,8 +996,7 @@ function resizeFBO(target, w, h, internalFormat, format, type, param)
return newFBO;
}
function resizeDoubleFBO(target, w, h, internalFormat, format, type, param)
{
function resizeDoubleFBO(target, w, h, internalFormat, format, type, param) {
if (target.width == w && target.height == h)
return target;
target.read = resizeFBO(target.read, w, h, internalFormat, format, type, param);
@ -1056,8 +1008,7 @@ function resizeDoubleFBO(target, w, h, internalFormat, format, type, param)
return target;
}
function createTextureAsync(url)
{
function createTextureAsync(url) {
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
@ -1070,8 +1021,7 @@ function createTextureAsync(url)
texture,
width: 1,
height: 1,
attach(id)
{
attach(id) {
gl.activeTexture(gl.TEXTURE0 + id);
gl.bindTexture(gl.TEXTURE_2D, texture);
return id;
@ -1079,8 +1029,7 @@ function createTextureAsync(url)
};
let image = new Image();
image.onload = () =>
{
image.onload = () => {
obj.width = image.width;
obj.height = image.height;
gl.bindTexture(gl.TEXTURE_2D, texture);
@ -1091,8 +1040,7 @@ function createTextureAsync(url)
return obj;
}
function updateKeywords()
{
function updateKeywords() {
let displayKeywords = [];
if (config.SHADING) displayKeywords.push("SHADING");
if (config.BLOOM) displayKeywords.push("BLOOM");
@ -1108,8 +1056,7 @@ let lastUpdateTime = Date.now();
let colorUpdateTimer = 0.0;
update();
function update()
{
function update() {
const dt = calcDeltaTime();
if (resizeCanvas())
initFramebuffers();
@ -1121,8 +1068,7 @@ function update()
requestAnimationFrame(update);
}
function calcDeltaTime()
{
function calcDeltaTime() {
let now = Date.now();
let dt = (now - lastUpdateTime) / 1000;
dt = Math.min(dt, 0.016666);
@ -1130,12 +1076,10 @@ function calcDeltaTime()
return dt;
}
function resizeCanvas()
{
function resizeCanvas() {
let width = scaleByPixelRatio(canvas.clientWidth);
let height = scaleByPixelRatio(canvas.clientHeight);
if (canvas.width != width || canvas.height != height)
{
if (canvas.width != width || canvas.height != height) {
canvas.width = width;
canvas.height = height;
return true;
@ -1143,38 +1087,31 @@ function resizeCanvas()
return false;
}
function updateColors(dt)
{
function updateColors(dt) {
if (!config.COLORFUL) return;
colorUpdateTimer += dt * config.COLOR_UPDATE_SPEED;
if (colorUpdateTimer >= 1)
{
if (colorUpdateTimer >= 1) {
colorUpdateTimer = wrap(colorUpdateTimer, 0, 1);
pointers.forEach(p =>
{
pointers.forEach(p => {
p.color = generateColor();
});
}
}
function applyInputs()
{
function applyInputs() {
if (splatStack.length > 0)
multipleSplats(splatStack.pop());
pointers.forEach(p =>
{
if (p.moved)
{
pointers.forEach(p => {
if (p.moved) {
p.moved = false;
splatPointer(p);
}
});
}
function step(dt)
{
function step(dt) {
gl.disable(gl.BLEND);
curlProgram.bind();
@ -1205,8 +1142,7 @@ function step(dt)
pressureProgram.bind();
gl.uniform2f(pressureProgram.uniforms.texelSize, velocity.texelSizeX, velocity.texelSizeY);
gl.uniform1i(pressureProgram.uniforms.uDivergence, divergence.attach(0));
for (let i = 0; i < config.PRESSURE_ITERATIONS; i++)
{
for (let i = 0; i < config.PRESSURE_ITERATIONS; i++) {
gl.uniform1i(pressureProgram.uniforms.uPressure, pressure.read.attach(1));
blit(pressure.write);
pressure.swap();
@ -1240,23 +1176,19 @@ function step(dt)
dye.swap();
}
function render(target)
{
function render(target) {
if (config.BLOOM)
applyBloom(dye.read, bloom);
if (config.SUNRAYS)
{
if (config.SUNRAYS) {
applySunrays(dye.read, dye.write, sunrays);
blur(sunrays, sunraysTemp, 1);
}
if (target == null || !config.TRANSPARENT)
{
if (target == null || !config.TRANSPARENT) {
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
}
else
{
else {
gl.disable(gl.BLEND);
}
@ -1267,22 +1199,19 @@ function render(target)
drawDisplay(target);
}
function drawColor(target, color)
{
function drawColor(target, color) {
colorProgram.bind();
gl.uniform4f(colorProgram.uniforms.color, color.r, color.g, color.b, 1);
blit(target);
}
function drawCheckerboard(target)
{
function drawCheckerboard(target) {
checkerboardProgram.bind();
gl.uniform1f(checkerboardProgram.uniforms.aspectRatio, canvas.width / canvas.height);
blit(target);
}
function drawDisplay(target)
{
function drawDisplay(target) {
let width = target == null ? gl.drawingBufferWidth : target.width;
let height = target == null ? gl.drawingBufferHeight : target.height;
@ -1290,8 +1219,7 @@ function drawDisplay(target)
if (config.SHADING)
gl.uniform2f(displayMaterial.uniforms.texelSize, 1.0 / width, 1.0 / height);
gl.uniform1i(displayMaterial.uniforms.uTexture, dye.read.attach(0));
if (config.BLOOM)
{
if (config.BLOOM) {
gl.uniform1i(displayMaterial.uniforms.uBloom, bloom.attach(1));
gl.uniform1i(displayMaterial.uniforms.uDithering, ditheringTexture.attach(2));
let scale = getTextureScale(ditheringTexture, width, height);
@ -1302,8 +1230,7 @@ function drawDisplay(target)
blit(target);
}
function applyBloom(source, destination)
{
function applyBloom(source, destination) {
if (bloomFramebuffers.length < 2)
return;
@ -1321,8 +1248,7 @@ function applyBloom(source, destination)
blit(last);
bloomBlurProgram.bind();
for (let i = 0; i < bloomFramebuffers.length; i++)
{
for (let i = 0; i < bloomFramebuffers.length; i++) {
let dest = bloomFramebuffers[i];
gl.uniform2f(bloomBlurProgram.uniforms.texelSize, last.texelSizeX, last.texelSizeY);
gl.uniform1i(bloomBlurProgram.uniforms.uTexture, last.attach(0));
@ -1333,8 +1259,7 @@ function applyBloom(source, destination)
gl.blendFunc(gl.ONE, gl.ONE);
gl.enable(gl.BLEND);
for (let i = bloomFramebuffers.length - 2; i >= 0; i--)
{
for (let i = bloomFramebuffers.length - 2; i >= 0; i--) {
let baseTex = bloomFramebuffers[i];
gl.uniform2f(bloomBlurProgram.uniforms.texelSize, last.texelSizeX, last.texelSizeY);
gl.uniform1i(bloomBlurProgram.uniforms.uTexture, last.attach(0));
@ -1351,8 +1276,7 @@ function applyBloom(source, destination)
blit(destination);
}
function applySunrays(source, mask, destination)
{
function applySunrays(source, mask, destination) {
gl.disable(gl.BLEND);
sunraysMaskProgram.bind();
gl.uniform1i(sunraysMaskProgram.uniforms.uTexture, source.attach(0));
@ -1364,11 +1288,9 @@ function applySunrays(source, mask, destination)
blit(destination);
}
function blur(target, temp, iterations)
{
function blur(target, temp, iterations) {
blurProgram.bind();
for (let i = 0; i < iterations; i++)
{
for (let i = 0; i < iterations; i++) {
gl.uniform2f(blurProgram.uniforms.texelSize, target.texelSizeX, 0.0);
gl.uniform1i(blurProgram.uniforms.uTexture, target.attach(0));
blit(temp);
@ -1379,17 +1301,14 @@ function blur(target, temp, iterations)
}
}
function splatPointer(pointer)
{
function splatPointer(pointer) {
let dx = pointer.deltaX * config.SPLAT_FORCE;
let dy = pointer.deltaY * config.SPLAT_FORCE;
splat(pointer.texcoordX, pointer.texcoordY, dx, dy, pointer.color);
}
function multipleSplats(amount)
{
for (let i = 0; i < amount; i++)
{
function multipleSplats(amount) {
for (let i = 0; i < amount; i++) {
const color = generateColor();
color.r *= 10.0;
color.g *= 10.0;
@ -1402,8 +1321,7 @@ function multipleSplats(amount)
}
}
function splat(x, y, dx, dy, color)
{
function splat(x, y, dx, dy, color) {
splatProgram.bind();
gl.uniform1i(splatProgram.uniforms.uTarget, velocity.read.attach(0));
gl.uniform1f(splatProgram.uniforms.aspectRatio, canvas.width / canvas.height);
@ -1419,16 +1337,14 @@ function splat(x, y, dx, dy, color)
dye.swap();
}
function correctRadius(radius)
{
function correctRadius(radius) {
let aspectRatio = canvas.width / canvas.height;
if (aspectRatio > 1)
radius *= aspectRatio;
return radius;
}
canvas.addEventListener('mousedown', e =>
{
canvas.addEventListener('mousedown', e => {
let posX = scaleByPixelRatio(e.offsetX);
let posY = scaleByPixelRatio(e.offsetY);
let pointer = pointers.find(p => p.id == -1);
@ -1437,41 +1353,34 @@ canvas.addEventListener('mousedown', e =>
updatePointerDownData(pointer, -1, posX, posY);
});
setTimeout(() =>
{
canvas.addEventListener('mousemove', e =>
{
setTimeout(() => {
canvas.addEventListener('mousemove', e => {
let posX = scaleByPixelRatio(e.offsetX);
let posY = scaleByPixelRatio(e.offsetY);
updatePointerMoveData(pointers[0], posX, posY);
});
}, 500);
window.addEventListener('mouseup', () =>
{
window.addEventListener('mouseup', () => {
updatePointerUpData(pointers[0]);
});
canvas.addEventListener('touchstart', e =>
{
canvas.addEventListener('touchstart', e => {
e.preventDefault();
const touches = e.targetTouches;
while (touches.length >= pointers.length)
pointers.push(new pointerPrototype());
for (let i = 0; i < touches.length; i++)
{
for (let i = 0; i < touches.length; i++) {
let posX = scaleByPixelRatio(touches[i].pageX);
let posY = scaleByPixelRatio(touches[i].pageY);
updatePointerDownData(pointers[i + 1], touches[i].identifier, posX, posY);
}
});
canvas.addEventListener('touchmove', e =>
{
canvas.addEventListener('touchmove', e => {
e.preventDefault();
const touches = e.targetTouches;
for (let i = 0; i < touches.length; i++)
{
for (let i = 0; i < touches.length; i++) {
let pointer = pointers[i + 1];
if (!pointer.down) continue;
let posX = scaleByPixelRatio(touches[i].pageX);
@ -1480,27 +1389,23 @@ canvas.addEventListener('touchmove', e =>
}
}, false);
window.addEventListener('touchend', e =>
{
window.addEventListener('touchend', e => {
const touches = e.changedTouches;
for (let i = 0; i < touches.length; i++)
{
for (let i = 0; i < touches.length; i++) {
let pointer = pointers.find(p => p.id == touches[i].identifier);
if (pointer == null) continue;
updatePointerUpData(pointer);
}
});
window.addEventListener('keydown', e =>
{
window.addEventListener('keydown', e => {
if (e.code === 'KeyP')
config.PAUSED = !config.PAUSED;
if (e.key === ' ')
splatStack.push(parseInt(Math.random() * 20) + 5);
});
function updatePointerDownData(pointer, id, posX, posY)
{
function updatePointerDownData(pointer, id, posX, posY) {
pointer.id = id;
pointer.down = true;
pointer.moved = false;
@ -1513,8 +1418,7 @@ function updatePointerDownData(pointer, id, posX, posY)
pointer.color = generateColor();
}
function updatePointerMoveData(pointer, posX, posY)
{
function updatePointerMoveData(pointer, posX, posY) {
pointer.prevTexcoordX = pointer.texcoordX;
pointer.prevTexcoordY = pointer.texcoordY;
pointer.texcoordX = posX / canvas.width;
@ -1524,27 +1428,23 @@ function updatePointerMoveData(pointer, posX, posY)
pointer.moved = Math.abs(pointer.deltaX) > 0 || Math.abs(pointer.deltaY) > 0;
}
function updatePointerUpData(pointer)
{
function updatePointerUpData(pointer) {
pointer.down = false;
}
function correctDeltaX(delta)
{
function correctDeltaX(delta) {
let aspectRatio = canvas.width / canvas.height;
if (aspectRatio < 1) delta *= aspectRatio;
return delta;
}
function correctDeltaY(delta)
{
function correctDeltaY(delta) {
let aspectRatio = canvas.width / canvas.height;
if (aspectRatio > 1) delta /= aspectRatio;
return delta;
}
function generateColor()
{
function generateColor() {
let c = HSVtoRGB(Math.random(), 1.0, 1.0);
c.r *= 0.15;
c.g *= 0.15;
@ -1552,8 +1452,7 @@ function generateColor()
return c;
}
function HSVtoRGB(h, s, v)
{
function HSVtoRGB(h, s, v) {
let r, g, b, i, f, p, q, t;
i = Math.floor(h * 6);
f = h * 6 - i;
@ -1561,8 +1460,7 @@ function HSVtoRGB(h, s, v)
q = v * (1 - f * s);
t = v * (1 - (1 - f) * s);
switch (i % 6)
{
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
@ -1578,8 +1476,7 @@ function HSVtoRGB(h, s, v)
};
}
function normalizeColor(input)
{
function normalizeColor(input) {
let output = {
r: input.r / 255,
g: input.g / 255,
@ -1588,15 +1485,13 @@ function normalizeColor(input)
return output;
}
function wrap(value, min, max)
{
function wrap(value, min, max) {
let range = max - min;
if (range == 0) return min;
return (value - min) % range + min;
}
function getResolution(resolution)
{
function getResolution(resolution) {
let aspectRatio = gl.drawingBufferWidth / gl.drawingBufferHeight;
if (aspectRatio < 1)
aspectRatio = 1.0 / aspectRatio;
@ -1610,26 +1505,22 @@ function getResolution(resolution)
return { width: min, height: max };
}
function getTextureScale(texture, width, height)
{
function getTextureScale(texture, width, height) {
return {
x: width / texture.width,
y: height / texture.height
};
}
function scaleByPixelRatio(input)
{
function scaleByPixelRatio(input) {
let pixelRatio = window.devicePixelRatio || 1;
return Math.floor(input * pixelRatio);
}
function hashCode(s)
{
function hashCode(s) {
if (s.length == 0) return 0;
let hash = 0;
for (let i = 0; i < s.length; i++)
{
for (let i = 0; i < s.length; i++) {
hash = (hash << 5) - hash + s.charCodeAt(i);
hash |= 0; // Convert to 32bit integer
}