Created
September 16, 2012 06:45
-
-
Save philogb/3731312 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.addEventListener('load', function() { | |
var section = document.querySelector('div.main'), | |
args = document.querySelector('div.arguments'), | |
controls = document.querySelector('.controls'), | |
image = args.querySelector('img'), | |
video = args.querySelector('video'), | |
log = $('log'), | |
useBloomX = true, | |
useBloomY = true, | |
useBlending = true; | |
//check support | |
if (!supportsWebGL()) { | |
log.innerHTML = '<p class=\'error\'>Your browser doesn\'t seem to support WebGL. More info <a href=\'http://get.webgl.org/\'>here</a>.</p>'; | |
return; | |
} | |
//add events | |
$('useBloomX').addEventListener('change', function() { | |
useBloomX = this.checked; | |
}); | |
$('useBloomY').addEventListener('change', function() { | |
useBloomY = this.checked; | |
}); | |
$('useBlending').addEventListener('change', function() { | |
useBlending = this.checked; | |
}); | |
//get context | |
var canvas = $('webgl-canvas'), | |
gl = getWebGLContext(canvas), | |
useVideo; | |
createProgramsFromURIs(gl, { | |
programs: [{ | |
name: 'bloom', | |
vsURI: 'shaders/simple.vs', | |
fsURI: 'shaders/bloom.fs' | |
}, { | |
name: 'blend', | |
vsURI: 'shaders/simple.vs', | |
fsURI: 'shaders/blend.fs' | |
}], | |
onComplete: function(programs) { | |
//try adding video input, if not fallback to image | |
useVideo = setupCamera(); | |
if (!useVideo) { | |
image.style.display = ''; | |
render(programs); | |
} else { | |
controls.style.display = ''; | |
video.addEventListener('loadeddata', render.bind(null, programs)); | |
} | |
} | |
}); | |
function setupCamera(callback) { | |
var getUserMediaKey = ['getUserMedia', 'webkitGetUserMedia', 'mozGetUserMedia'], | |
urlKey = ['URL', 'webkitURL', 'mozURL'], | |
found = false, | |
videoHandler = function(localMediaStream) { | |
video.style.display = ''; | |
video.src = window[urlKey[i]].createObjectURL(localMediaStream); | |
video.play(); | |
}, | |
videoHandler2 = function(stream) { | |
video.style.display = ''; | |
video.src = stream; | |
video.play(); | |
}, | |
errorHandler = function() { | |
log.innerHTML = 'An error occurred while loading the camera. Please refresh and try again.'; | |
}, | |
key; | |
for (var i = 0, l = getUserMediaKey.length; i < l; ++i) { | |
key = getUserMediaKey[i]; | |
if (key in navigator) { | |
if (i > 0) { | |
navigator[key]({ video: true }, videoHandler, errorHandler); | |
} else { | |
navigator[key]({ video: true }, videoHandler2, errorHandler); | |
} | |
found = true; | |
break; | |
} | |
} | |
return found; | |
} | |
function render(programs) { | |
var buffer = gl.createBuffer(), | |
vertices = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1], | |
inputTexture = createTexture(gl, useVideo ? video : image), | |
bloomXFramebuffer = createFramebuffer(gl, useVideo ? video : image), | |
bloomYFramebuffer = createFramebuffer(gl, useVideo ? video : image), | |
x, y; | |
//set position attribute data | |
gl.bindBuffer(gl.ARRAY_BUFFER, buffer); | |
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); | |
//set image as texture and render only once | |
if (!useVideo) { | |
log.innerHTML = 'Your browser doesn\'t seem to support getUserMedia, using HTMLImage.'; | |
section.style.width = image.offsetWidth + 'px'; | |
section.style.height = image.offsetHeight + 'px'; | |
postProcess({ | |
gl: gl, | |
programs: programs, | |
quad: buffer, | |
input: image, | |
inputTexture: inputTexture, | |
bloomXFramebuffer: bloomXFramebuffer, | |
bloomYFramebuffer: bloomYFramebuffer | |
}); | |
return; | |
} | |
window.requestAnimationFrame(function loop() { | |
canvas.width = video.offsetWidth; | |
canvas.height = video.offsetHeight; | |
section.style.width = canvas.width + 'px'; | |
section.style.height = canvas.height + 'px'; | |
gl.viewport(0, 0, canvas.width, canvas.height); | |
postProcess({ | |
gl: gl, | |
programs: programs, | |
quad: buffer, | |
input: video, | |
inputTexture: inputTexture, | |
bloomXFramebuffer: bloomXFramebuffer, | |
bloomYFramebuffer: bloomYFramebuffer | |
}); | |
//request next frame to render | |
window.requestAnimationFrame(loop); | |
}); | |
} | |
function postProcess(opt) { | |
var gl = opt.gl, | |
programs = opt.programs, | |
quad = opt.quad, | |
input = opt.input, | |
inputTexture = opt.inputTexture, | |
bloomXFramebuffer = opt.bloomXFramebuffer, | |
bloomYFramebuffer = opt.bloomYFramebuffer, | |
canvas = gl.canvas, | |
widthLocation, | |
heightLocation, | |
samplerLocation, | |
samplerLocation0, | |
samplerLocation1, | |
positionLocation, | |
useBlendingLocation, | |
currentProgram; | |
//1.- first pass | |
currentProgram = programs.bloom, | |
gl.bindFramebuffer(gl.FRAMEBUFFER, bloomXFramebuffer.buffer); | |
gl.useProgram(currentProgram); | |
gl.bindBuffer(gl.ARRAY_BUFFER, quad); | |
//set uniform data | |
widthLocation = gl.getUniformLocation(currentProgram, 'width'); | |
heightLocation = gl.getUniformLocation(currentProgram, 'height'); | |
blurXLocation = gl.getUniformLocation(currentProgram, 'blurX'); | |
blurYLocation = gl.getUniformLocation(currentProgram, 'blurY'); | |
samplerLocation = gl.getUniformLocation(currentProgram, 'sampler0'); | |
positionLocation = gl.getAttribLocation(currentProgram, 'position'); | |
gl.enableVertexAttribArray(positionLocation); | |
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); | |
gl.uniform1f(widthLocation, canvas.width); | |
gl.uniform1f(heightLocation, canvas.height); | |
gl.uniform1f(blurXLocation, useBloomX ? 1 : 0); | |
gl.uniform1f(blurYLocation, 0); | |
gl.uniform1i(samplerLocation, 0); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, inputTexture); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, input); | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
//send result to bloomX framebuffer | |
gl.bindTexture(gl.TEXTURE_2D, bloomXFramebuffer.texture); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, null); | |
//2.- second pass | |
gl.bindFramebuffer(gl.FRAMEBUFFER, bloomYFramebuffer.buffer); | |
gl.uniform1f(blurXLocation, 0); | |
gl.uniform1f(blurYLocation, useBloomY ? 1 : 0); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, bloomXFramebuffer.texture); | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
//send result to bloomY framebuffer | |
gl.bindTexture(gl.TEXTURE_2D, bloomYFramebuffer.texture); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, null); | |
//3.- blend texture with current output, add tone mapping and send to screen | |
currentProgram = programs.blend; | |
gl.useProgram(currentProgram); | |
gl.bindBuffer(gl.ARRAY_BUFFER, quad); | |
//set uniform data | |
widthLocation = gl.getUniformLocation(currentProgram, 'width'); | |
heightLocation = gl.getUniformLocation(currentProgram, 'height'); | |
samplerLocation0 = gl.getUniformLocation(currentProgram, 'sampler0'); | |
samplerLocation1 = gl.getUniformLocation(currentProgram, 'sampler1'); | |
useBlendingLocation = gl.getUniformLocation(currentProgram, 'useBlending'); | |
positionLocation = gl.getAttribLocation(currentProgram, 'position'); | |
gl.enableVertexAttribArray(positionLocation); | |
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); | |
gl.uniform1f(widthLocation, canvas.width); | |
gl.uniform1f(heightLocation, canvas.height); | |
gl.uniform1i(samplerLocation0, 0); | |
gl.uniform1i(samplerLocation1, 1); | |
gl.uniform1i(useBlendingLocation, useBlending ? 1 : 0); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, bloomYFramebuffer.texture); | |
gl.activeTexture(gl.TEXTURE1); | |
gl.bindTexture(gl.TEXTURE_2D, inputTexture); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, input); | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
} | |
function createTexture(gl, size) { | |
var texture = gl.createTexture(); | |
//set properties for the texture | |
gl.bindTexture(gl.TEXTURE_2D, texture); | |
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_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size.offsetWidth, size.offsetHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
return texture; | |
} | |
function createFramebuffer(gl, size) { | |
var buffer = gl.createFramebuffer(); | |
//bind framebuffer to texture | |
gl.bindFramebuffer(gl.FRAMEBUFFER, buffer); | |
var texture = createTexture(gl, size); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); | |
return { | |
texture: texture, | |
buffer: buffer | |
}; | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment