/*
The MIT License (MIT)
Copyright (c) 2015 Patricio Gonzalez Vivo ( http://www.patriciogonzalezvivo.com )
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var timeLoad = Date.now();
var mouse = {x: 0, y: 0};
var billboards = [];
function isPowerOf2(value) {
return (value & (value - 1)) == 0;
};
function nextHighestPowerOfTwo(x) {
--x;
for (var i = 1; i < 32; i <<= 1) {
x = x | x >> i;
}
return x + 1;
}
function loadTexture(_gl, _texture) {
_gl.bindTexture(_gl.TEXTURE_2D, _texture);
_gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, true);
_gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.RGBA, _gl.RGBA, _gl.UNSIGNED_BYTE, _texture.image);
if (isPowerOf2(_texture.image.width) && isPowerOf2(_texture.image.height) ) {
_gl.generateMipmap(_gl.TEXTURE_2D);
_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.LINEAR);
_gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR_MIPMAP_LINEAR);
} else {
_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.LINEAR);
}
_gl.bindTexture(_gl.TEXTURE_2D, null);
}
function getMousePos(_canvas, _evt) {
var rect = _canvas.getBoundingClientRect();
return {
x: _evt.clientX - rect.left,
y: _evt.clientY - rect.top
};
}
function loadShaders() {
var list = document.getElementsByTagName("canvas");
// Load canvas and WebGLContexta
for(var i = 0; i < list.length; i++){
var shaderSrc = { vertURL: null, vertSTR: null,
fragURL: null, fragSTR: null };
if( list[i].hasAttribute("data-fragment") ){
shaderSrc.fragSTR = list[i].getAttribute('data-fragment');
} else if( list[i].hasAttribute("data-fragment-url") ){
shaderSrc.fragURL = list[i].getAttribute('data-fragment-url');
} else {
continue;
}
var canvas = list[i];
var gl;
if( !billboards[i] || !billboards[i].gl){
console.log("Creating WebGL context");
gl = setupWebGL(list[i]);
} else {
gl = billboards[i].gl
}
var program = loadShader(gl, shaderSrc);
if(!program){
if(billboards[i].program){
program = billboards[i].program;
} else {
billboards[i] = null;
return;
}
} else if ( billboards[i] && billboards[i].program ){
billboards[i].gl.deleteProgram(billboards[i].program);
}
var vbo = [];
if ( !billboards[i] || !billboards[i].vbo){
console.log("Creating Vbo");
// Define UVS buffer
var uvs;
var texCoordLocation = gl.getAttribLocation(program, "a_texcoord");
uvs = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, uvs);
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array([0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray( texCoordLocation );
gl.vertexAttribPointer( texCoordLocation, 2, gl.FLOAT, false, 0, 0);
vbo.push(uvs);
// Define Vertex buffer
var vertices;
var positionLocation = gl.getAttribLocation(program, "a_position");
vertices = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, vertices);
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);
gl.enableVertexAttribArray( positionLocation );
gl.vertexAttribPointer( positionLocation , 2, gl.FLOAT, false, 0, 0);
vbo.push(vertices);
} else {
vbo = billboards[i].vbo;
}
// Clean texture
var textures = [];
// Need to load textures
var bLoadTextures = list[i].hasAttribute('data-textures');
if ( billboards[i] && billboards[i].textures && bLoadTextures){
var nImages = canvas.getAttribute('data-textures').split(',');
if (nImages.length === billboards[i].textures.length){
bLoadTextures = false;
for(var j in nImages){
if( billboards[i].textures[j].image.getAttribute("src") !== nImages[j] ){
bLoadTextures = true;
break;
}
}
}
if (!bLoadTextures){
textures = billboards[i].textures;
}
}
if( bLoadTextures ){
// Clean the texture array
while(textures.length > 0) {
console.log("Deleting texture: " + (textures.length-1));
gl.deleteTexture(textures[textures.length-1]);
textures.pop();
}
var imgList = list[i].getAttribute('data-textures').split(',');
for(var nImg in imgList){
console.log("Loading texture: " + imgList[nImg]);
textures.push(gl.createTexture());
gl.bindTexture(gl.TEXTURE_2D, textures[nImg]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 0, 255])); // red
textures[nImg].image = new Image();
textures[nImg].image.onload = function(_gl,_tex) {
return function() {
loadTexture(_gl, _tex);
};
}(gl,textures[nImg]);
textures[nImg].image.src = imgList[nImg];
}
}
// Assign canvas, gl context, shader, UV/Verts buffers and animate boolean to billboard
billboards[i] = { canvas: canvas,
gl: gl,
program: program,
vbo: vbo,
textures: textures,
mouse: mouse };
}
}
function renderShaders(){
for(var i = 0; i < billboards.length; i++){
// If there is something on the billboard
if(billboards[i]){
renderShader( billboards[i] );
}
}
window.requestAnimFrame(renderShaders);
}
/**
* Creates the HTLM for a failure message
* @param {string} canvasContainerId id of container of th
* canvas.
* @return {string} The html.
*/
var makeFailHTML = function(msg) {
return '' +
'
';
};
/**
* Mesasge for getting a webgl browser
* @type {string}
*/
var GET_A_WEBGL_BROWSER = '' +
'This page requires a browser that supports WebGL.
' +
'Click here to upgrade your browser.';
/**
* Mesasge for need better hardware
* @type {string}
*/
var OTHER_PROBLEM = '' +
"It doesn't appear your computer can support WebGL.
" +
'Click here for more information.';
/**
* Creates a webgl context. If creation fails it will
* change the contents of the container of the