diff --git a/v1-com-officielle/glitcher/glitcher.js b/v1-com-officielle/glitcher/glitcher.js index f7ad40b..17a9e49 100644 --- a/v1-com-officielle/glitcher/glitcher.js +++ b/v1-com-officielle/glitcher/glitcher.js @@ -1,14 +1,16 @@ import { Glitcher } from "./lib/glitcher"; -const UI_GLITCHER = new Glitcher(document.getElementById("ui-canvas")) +const CANVAS = document.getElementById("ui-canvas") +const UI_GLITCHER = new Glitcher(CANVAS) const FORM = document.getElementById("glitcher-form") async function updateFromForm(){ let data = new FormData(FORM) let image = data.get("image") - if(image){ + if(image.size > 0){ await UI_GLITCHER.setImage(image) + UI_GLITCHER.clearGlitch() } else { UI_GLITCHER.clearImage() } @@ -25,4 +27,60 @@ FORM.addEventListener("submit", e => { updateFromForm() }) +CANVAS.addEventListener("pointerdown", e => { + let pointerId = e.pointerId; + + let lastX = undefined; + let lastY = undefined; + let lastCommit = null; + + function applyGlitch(e){ + if(e.pointerId != pointerId){ + return + } + + let canvasRect = CANVAS.getBoundingClientRect() + let x = e.clientX - canvasRect.left + let y = e.clientY - canvasRect.top + + let now = Date.now() + + if(lastCommit === null || now - lastCommit > 100){ + let width = 20; + if(e.pointerType == "touch"){ + width *= 2 + } + + let deltaX = lastX !== undefined ? x - lastX : 0 + let deltaY = lastY !== undefined ? y - lastY : 0 + + width += Math.max(Math.abs(deltaX), Math.abs(deltaY)) + + //UI_GLITCHER.addGlitch(x + (Math.random() * width) - width/2, y + (Math.random() * width) - width/2, width) + UI_GLITCHER.addGlitch(x, y, width) + UI_GLITCHER.render() + + lastCommit = now + } + + lastX = x + lastY = y + } + + function endGlitch(e){ + if(e.pointerId != pointerId){ + return + } + + window.removeEventListener("pointermove", applyGlitch) + window.removeEventListener("pointerup", endGlitch) + } + + window.addEventListener("pointerup", endGlitch) + window.addEventListener("pointermove", applyGlitch) + + applyGlitch(e) +}) + + updateFromForm() \ No newline at end of file diff --git a/v1-com-officielle/glitcher/lib/base.vert b/v1-com-officielle/glitcher/lib/base.vert index 395c746..cc2aaff 100644 --- a/v1-com-officielle/glitcher/lib/base.vert +++ b/v1-com-officielle/glitcher/lib/base.vert @@ -1,9 +1,9 @@ -attribute vec4 aVertexPosition; +attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; varying highp vec2 vTextureCoord; void main() { - gl_Position = aVertexPosition; + gl_Position = vec4(aVertexPosition, 0.0, 1.0); vTextureCoord = aTextureCoord; } diff --git a/v1-com-officielle/glitcher/lib/glitch.frag b/v1-com-officielle/glitcher/lib/glitch.frag new file mode 100644 index 0000000..45da7f3 --- /dev/null +++ b/v1-com-officielle/glitcher/lib/glitch.frag @@ -0,0 +1,3 @@ +void main() { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); +} \ No newline at end of file diff --git a/v1-com-officielle/glitcher/lib/glitch.vert b/v1-com-officielle/glitcher/lib/glitch.vert new file mode 100644 index 0000000..847dc61 --- /dev/null +++ b/v1-com-officielle/glitcher/lib/glitch.vert @@ -0,0 +1,17 @@ +attribute vec4 aVertexPosition; + +uniform vec2 uGlitchPosition; +uniform float uGlitchWidth; +uniform vec2 uImageRatio; + +void main() { + vec2 vertex = aVertexPosition.xy; + + vertex *= uImageRatio; + vertex *= 0.001; + vertex *= uGlitchWidth; + vertex += uGlitchPosition; + + gl_Position = vec4(vertex, -1.0, 1.0); +} + diff --git a/v1-com-officielle/glitcher/lib/glitcher.js b/v1-com-officielle/glitcher/lib/glitcher.js index 798e69a..4ead33d 100644 --- a/v1-com-officielle/glitcher/lib/glitcher.js +++ b/v1-com-officielle/glitcher/lib/glitcher.js @@ -1,12 +1,18 @@ -import resizeToFit from 'intrinsic-scale'; +import resizeToFit from 'intrinsic-scale' + import baseVertSource from "./base.vert?raw" import baseFragSource from "./base.frag?raw" +import glitchVertSource from "./glitch.vert?raw" +import glitchFragSource from "./glitch.frag?raw" + export class Glitcher { /** @type {HTMLCanvasElement} */ canvas + gliches = [] + /** * @param {HTMLCanvasElement} canvas */ @@ -21,35 +27,7 @@ export class Glitcher { throw new Error("WebGL isn't supported") } - let baseVertShader = this.ctx.createShader(this.ctx.VERTEX_SHADER) - this.ctx.shaderSource(baseVertShader, baseVertSource) - this.ctx.compileShader(baseVertShader) - - if (!this.ctx.getShaderParameter(baseVertShader, this.ctx.COMPILE_STATUS)) { - throw new Error(`failed to compile base.vert: ${this.ctx.getShaderInfoLog(baseVertShader)}`) - } - - let baseFragShader = this.ctx.createShader(this.ctx.FRAGMENT_SHADER) - this.ctx.shaderSource(baseFragShader, baseFragSource) - this.ctx.compileShader(baseFragShader) - - if (!this.ctx.getShaderParameter(baseFragShader, this.ctx.COMPILE_STATUS)) { - throw new Error(`failed to compile base.frag: ${this.ctx.getShaderInfoLog(baseFragShader)}`) - } - - let baseShaderProgram = this.ctx.createProgram() - this.ctx.attachShader(baseShaderProgram, baseVertShader) - this.ctx.attachShader(baseShaderProgram, baseFragShader) - this.ctx.linkProgram(baseShaderProgram) - - if (!this.ctx.getProgramParameter(baseShaderProgram, this.ctx.LINK_STATUS)) { - throw new Error(`failed to link base shaders: ${this.ctx.getProgramInfoLog(baseShaderProgram)}`) - } - - this.baseProgram = baseShaderProgram; - this.aVertexPosition = this.ctx.getAttribLocation(baseShaderProgram, "aVertexPosition") - this.aTextureCoord = this.ctx.getAttribLocation(baseShaderProgram, "aTextureCoord") - this.uImageSampler = this.ctx.getUniformLocation(baseShaderProgram, "uImageSampler") + let baseProgram = createProgram(this.ctx, baseVertSource, baseFragSource); let panelPositionBuffer = this.ctx.createBuffer() this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelPositionBuffer) @@ -60,7 +38,6 @@ export class Glitcher { 1.0, -1.0, ] this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(positions), this.ctx.STATIC_DRAW) - this.panelPositionsBuffer = panelPositionBuffer let panelUVBuffer = this.ctx.createBuffer() this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelUVBuffer) @@ -71,11 +48,41 @@ export class Glitcher { 1.0, 1.0, ] this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(uv), this.ctx.STATIC_DRAW) - this.panelUVBuffer = panelUVBuffer let imageTexture = this.ctx.createTexture() - this.imageTexture = imageTexture; + + this.base = { + program: baseProgram, + aVertexPosition: this.ctx.getAttribLocation(baseProgram, "aVertexPosition"), + aTextureCoord: this.ctx.getAttribLocation(baseProgram, "aTextureCoord"), + uImageSampler: this.ctx.getUniformLocation(baseProgram, "uImageSampler"), + imageTexture: imageTexture, + panelUVBuffer: panelUVBuffer, + panelPositionsBuffer: panelPositionBuffer + } this.clearImage(); + + + let glitchPositionBuffer = this.ctx.createBuffer() + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, glitchPositionBuffer) + const glitchPosition = [ + -1.0, 1.0, + 1.0, 1.0, + -1.0, -1.0, + 1.0, -1.0, + ] + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(glitchPosition), this.ctx.STATIC_DRAW) + + let glitchProgram = createProgram(this.ctx, glitchVertSource, glitchFragSource) + + this.glitch = { + program: glitchProgram, + aVertexPosition: this.ctx.getAttribLocation(glitchProgram, "aVertexPosition"), + uGlitchPosition: this.ctx.getUniformLocation(glitchProgram, "uGlitchPosition"), + uGlitchWidth: this.ctx.getUniformLocation(glitchProgram, "uGlitchWidth"), + uImageRatio: this.ctx.getUniformLocation(glitchProgram, "uImageRatio"), + glitchPositionBuffer: glitchPositionBuffer + } } clearImage(){ @@ -92,6 +99,22 @@ export class Glitcher { ) } + clearGlitch(){ + this.glitches = [] + } + + addGlitch(x, y, width=1){ + let computedStyle = window.getComputedStyle(this.canvas) + let clientWidth = parseFloat(computedStyle.width) + let clientHeight = parseFloat(computedStyle.height) + + this.glitches.push({ + x: ((x*2)/clientWidth)-1, + y: (((y*2)/clientHeight)-1)*-1, + width + }) + } + /** * @param {File} imageFile */ @@ -132,7 +155,7 @@ export class Glitcher { this.currentImageFile = imageFile this.currentImage = image - this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture) + this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.base.imageTexture) this.ctx.texImage2D( this.ctx.TEXTURE_2D, 0, @@ -184,38 +207,99 @@ export class Glitcher { this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT) - this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.panelPositionsBuffer) - this.ctx.vertexAttribPointer( - this.aVertexPosition, - 2, // N components per iteration - this.ctx.FLOAT, - false, //Normalize, - 0, // (stride) how many bytes to get from one set of values to the next - 0, // Start offset - ) - this.ctx.enableVertexAttribArray(this.aVertexPosition) - - this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.panelUVBuffer) - this.ctx.vertexAttribPointer( - this.aTextureCoord, - 2, - this.ctx.FLOAT, - false, - 0, - 0, - ) - this.ctx.enableVertexAttribArray(this.aTextureCoord) + { // Base rendering + this.ctx.useProgram(this.base.program) + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.base.panelPositionsBuffer) + this.ctx.vertexAttribPointer( + this.base.aVertexPosition, + 2, // N components per iteration + this.ctx.FLOAT, + false, //Normalize, + 0, // (stride) how many bytes to get from one set of values to the next + 0, // Start offset + ) + this.ctx.enableVertexAttribArray(this.base.aVertexPosition) + + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.base.panelUVBuffer) + this.ctx.vertexAttribPointer( + this.base.aTextureCoord, + 2, + this.ctx.FLOAT, + false, + 0, + 0, + ) + this.ctx.enableVertexAttribArray(this.base.aTextureCoord) - this.ctx.activeTexture(this.ctx.TEXTURE0) - this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture) - this.ctx.uniform1i(this.uImageSampler, 0) + this.ctx.activeTexture(this.ctx.TEXTURE0) + this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.base.imageTexture) + + this.ctx.uniform1i(this.base.uImageSampler, 0) + + this.ctx.drawArrays( + this.ctx.TRIANGLE_STRIP, + 0, // Vertex offset + 4, // Total vertex + ); + } - this.ctx.useProgram(this.baseProgram) - - this.ctx.drawArrays( - this.ctx.TRIANGLE_STRIP, - 0, // Vertex offset - 4, // Total vertex - ); + { // Glitch rendering + this.ctx.useProgram(this.glitch.program) + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.glitch.glitchPositionBuffer) + this.ctx.vertexAttribPointer( + this.glitch.glitchPositionBuffer, + 2, // N components per iteration + this.ctx.FLOAT, + false, //Normalize, + 0, // (stride) how many bytes to get from one set of values to the next + 0, // Start offset + ) + + this.ctx.enableVertexAttribArray(this.glitch.aVertexPosition) + if(this.canvas.width > this.canvas.height){ + this.ctx.uniform2f(this.glitch.uImageRatio, 1.0, this.canvas.width/this.canvas.height) + } else { + this.ctx.uniform2f(this.glitch.uImageRatio, this.canvas.height/this.canvas.width, 1.0) + } + + for(let glitch of this.glitches) { + this.ctx.uniform2f(this.glitch.uGlitchPosition, glitch.x, glitch.y) + this.ctx.uniform1f(this.glitch.uGlitchWidth, glitch.width) + this.ctx.drawArrays( + this.ctx.TRIANGLE_STRIP, + 0, // Vertex offset + 4, // Total vertex + ); + } + } } +} + +function createProgram(gl, vertSource, fragSource){ + let vertShader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vertShader, vertSource) + gl.compileShader(vertShader) + + if (!gl.getShaderParameter(vertShader, gl.COMPILE_STATUS)) { + throw new Error(`failed to compile vertex: ${gl.getShaderInfoLog(vertShader)}`) + } + + let fragShader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fragShader, fragSource) + gl.compileShader(fragShader) + + if (!gl.getShaderParameter(fragShader, gl.COMPILE_STATUS)) { + throw new Error(`failed to compile fragment: ${gl.getShaderInfoLog(fragShader)}`) + } + + let program = gl.createProgram() + gl.attachShader(program, vertShader) + gl.attachShader(program, fragShader) + gl.linkProgram(program) + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(`failed to link shader: ${gl.getProgramInfoLog(program)}`) + } + + return program } \ No newline at end of file