Ajout d'entités "glitch" a la scene
This commit is contained in:
@@ -1,14 +1,16 @@
|
|||||||
import { Glitcher } from "./lib/glitcher";
|
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")
|
const FORM = document.getElementById("glitcher-form")
|
||||||
|
|
||||||
async function updateFromForm(){
|
async function updateFromForm(){
|
||||||
let data = new FormData(FORM)
|
let data = new FormData(FORM)
|
||||||
|
|
||||||
let image = data.get("image")
|
let image = data.get("image")
|
||||||
if(image){
|
if(image.size > 0){
|
||||||
await UI_GLITCHER.setImage(image)
|
await UI_GLITCHER.setImage(image)
|
||||||
|
UI_GLITCHER.clearGlitch()
|
||||||
} else {
|
} else {
|
||||||
UI_GLITCHER.clearImage()
|
UI_GLITCHER.clearImage()
|
||||||
}
|
}
|
||||||
@@ -25,4 +27,60 @@ FORM.addEventListener("submit", e => {
|
|||||||
updateFromForm()
|
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()
|
updateFromForm()
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
attribute vec4 aVertexPosition;
|
attribute vec2 aVertexPosition;
|
||||||
attribute vec2 aTextureCoord;
|
attribute vec2 aTextureCoord;
|
||||||
|
|
||||||
varying highp vec2 vTextureCoord;
|
varying highp vec2 vTextureCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = aVertexPosition;
|
gl_Position = vec4(aVertexPosition, 0.0, 1.0);
|
||||||
vTextureCoord = aTextureCoord;
|
vTextureCoord = aTextureCoord;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
void main() {
|
||||||
|
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
import resizeToFit from 'intrinsic-scale';
|
import resizeToFit from 'intrinsic-scale'
|
||||||
|
|
||||||
import baseVertSource from "./base.vert?raw"
|
import baseVertSource from "./base.vert?raw"
|
||||||
import baseFragSource from "./base.frag?raw"
|
import baseFragSource from "./base.frag?raw"
|
||||||
|
|
||||||
|
import glitchVertSource from "./glitch.vert?raw"
|
||||||
|
import glitchFragSource from "./glitch.frag?raw"
|
||||||
|
|
||||||
export class Glitcher {
|
export class Glitcher {
|
||||||
|
|
||||||
/** @type {HTMLCanvasElement} */
|
/** @type {HTMLCanvasElement} */
|
||||||
canvas
|
canvas
|
||||||
|
|
||||||
|
gliches = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {HTMLCanvasElement} canvas
|
* @param {HTMLCanvasElement} canvas
|
||||||
*/
|
*/
|
||||||
@@ -21,35 +27,7 @@ export class Glitcher {
|
|||||||
throw new Error("WebGL isn't supported")
|
throw new Error("WebGL isn't supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
let baseVertShader = this.ctx.createShader(this.ctx.VERTEX_SHADER)
|
let baseProgram = createProgram(this.ctx, baseVertSource, baseFragSource);
|
||||||
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 panelPositionBuffer = this.ctx.createBuffer()
|
let panelPositionBuffer = this.ctx.createBuffer()
|
||||||
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelPositionBuffer)
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelPositionBuffer)
|
||||||
@@ -60,7 +38,6 @@ export class Glitcher {
|
|||||||
1.0, -1.0,
|
1.0, -1.0,
|
||||||
]
|
]
|
||||||
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(positions), this.ctx.STATIC_DRAW)
|
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(positions), this.ctx.STATIC_DRAW)
|
||||||
this.panelPositionsBuffer = panelPositionBuffer
|
|
||||||
|
|
||||||
let panelUVBuffer = this.ctx.createBuffer()
|
let panelUVBuffer = this.ctx.createBuffer()
|
||||||
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelUVBuffer)
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, panelUVBuffer)
|
||||||
@@ -71,11 +48,41 @@ export class Glitcher {
|
|||||||
1.0, 1.0,
|
1.0, 1.0,
|
||||||
]
|
]
|
||||||
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(uv), this.ctx.STATIC_DRAW)
|
this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(uv), this.ctx.STATIC_DRAW)
|
||||||
this.panelUVBuffer = panelUVBuffer
|
|
||||||
|
|
||||||
let imageTexture = this.ctx.createTexture()
|
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();
|
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(){
|
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
|
* @param {File} imageFile
|
||||||
*/
|
*/
|
||||||
@@ -132,7 +155,7 @@ export class Glitcher {
|
|||||||
this.currentImageFile = imageFile
|
this.currentImageFile = imageFile
|
||||||
this.currentImage = image
|
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.texImage2D(
|
||||||
this.ctx.TEXTURE_2D,
|
this.ctx.TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
@@ -184,38 +207,99 @@ export class Glitcher {
|
|||||||
|
|
||||||
this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT)
|
this.ctx.clear(this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT)
|
||||||
|
|
||||||
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.panelPositionsBuffer)
|
{ // Base rendering
|
||||||
this.ctx.vertexAttribPointer(
|
this.ctx.useProgram(this.base.program)
|
||||||
this.aVertexPosition,
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.base.panelPositionsBuffer)
|
||||||
2, // N components per iteration
|
this.ctx.vertexAttribPointer(
|
||||||
this.ctx.FLOAT,
|
this.base.aVertexPosition,
|
||||||
false, //Normalize,
|
2, // N components per iteration
|
||||||
0, // (stride) how many bytes to get from one set of values to the next
|
this.ctx.FLOAT,
|
||||||
0, // Start offset
|
false, //Normalize,
|
||||||
)
|
0, // (stride) how many bytes to get from one set of values to the next
|
||||||
this.ctx.enableVertexAttribArray(this.aVertexPosition)
|
0, // Start offset
|
||||||
|
)
|
||||||
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.panelUVBuffer)
|
this.ctx.enableVertexAttribArray(this.base.aVertexPosition)
|
||||||
this.ctx.vertexAttribPointer(
|
|
||||||
this.aTextureCoord,
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.base.panelUVBuffer)
|
||||||
2,
|
this.ctx.vertexAttribPointer(
|
||||||
this.ctx.FLOAT,
|
this.base.aTextureCoord,
|
||||||
false,
|
2,
|
||||||
0,
|
this.ctx.FLOAT,
|
||||||
0,
|
false,
|
||||||
)
|
0,
|
||||||
this.ctx.enableVertexAttribArray(this.aTextureCoord)
|
0,
|
||||||
|
)
|
||||||
|
this.ctx.enableVertexAttribArray(this.base.aTextureCoord)
|
||||||
|
|
||||||
this.ctx.activeTexture(this.ctx.TEXTURE0)
|
this.ctx.activeTexture(this.ctx.TEXTURE0)
|
||||||
this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.imageTexture)
|
this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.base.imageTexture)
|
||||||
this.ctx.uniform1i(this.uImageSampler, 0)
|
|
||||||
|
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)
|
{ // Glitch rendering
|
||||||
|
this.ctx.useProgram(this.glitch.program)
|
||||||
this.ctx.drawArrays(
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.glitch.glitchPositionBuffer)
|
||||||
this.ctx.TRIANGLE_STRIP,
|
this.ctx.vertexAttribPointer(
|
||||||
0, // Vertex offset
|
this.glitch.glitchPositionBuffer,
|
||||||
4, // Total vertex
|
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
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user