Commit initial. Import depuis webgl-tp6
This commit is contained in:
commit
063ceb5293
7 changed files with 3059 additions and 0 deletions
603
J3DI.js
Normal file
603
J3DI.js
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// initWebGL
|
||||||
|
//
|
||||||
|
// Initialize the Canvas element with the passed name as a WebGL object and return the
|
||||||
|
// WebGLRenderingContext.
|
||||||
|
function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
|
||||||
|
{
|
||||||
|
var canvas = document.getElementById(canvasName);
|
||||||
|
return gl = WebGLUtils.setupWebGL(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(msg) {
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load shaders with the passed names and create a program with them. Return this program
|
||||||
|
// in the 'program' property of the returned context.
|
||||||
|
//
|
||||||
|
// For each string in the passed attribs array, bind an attrib with that name at that index.
|
||||||
|
// Once the attribs are bound, link the program and then use it.
|
||||||
|
//
|
||||||
|
// Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
|
||||||
|
// Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
|
||||||
|
//
|
||||||
|
// A console function is added to the context: console(string). This can be replaced
|
||||||
|
// by the caller. By default, it maps to the window.console() function on WebKit and to
|
||||||
|
// an empty function on other browsers.
|
||||||
|
//
|
||||||
|
function simpleSetup(gl, vshader, fshader, attribs, clearColor, clearDepth)
|
||||||
|
{
|
||||||
|
// create our shaders
|
||||||
|
var vertexShader = loadShader(gl, vshader);
|
||||||
|
var fragmentShader = loadShader(gl, fshader);
|
||||||
|
|
||||||
|
// Create the program object
|
||||||
|
var program = gl.createProgram();
|
||||||
|
|
||||||
|
// Attach our two shaders to the program
|
||||||
|
gl.attachShader (program, vertexShader);
|
||||||
|
gl.attachShader (program, fragmentShader);
|
||||||
|
|
||||||
|
// Bind attributes
|
||||||
|
for (var i = 0; i < attribs.length; ++i)
|
||||||
|
gl.bindAttribLocation (program, i, attribs[i]);
|
||||||
|
|
||||||
|
// Link the program
|
||||||
|
gl.linkProgram(program);
|
||||||
|
|
||||||
|
// Check the link status
|
||||||
|
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
|
||||||
|
if (!linked && !gl.isContextLost()) {
|
||||||
|
// something went wrong with the link
|
||||||
|
var error = gl.getProgramInfoLog (program);
|
||||||
|
log("Error in program linking:"+error);
|
||||||
|
|
||||||
|
gl.deleteProgram(program);
|
||||||
|
gl.deleteProgram(fragmentShader);
|
||||||
|
gl.deleteProgram(vertexShader);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
gl.useProgram(program);
|
||||||
|
|
||||||
|
gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
||||||
|
gl.clearDepth(clearDepth);
|
||||||
|
|
||||||
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
gl.enable(gl.BLEND);
|
||||||
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// loadShader
|
||||||
|
//
|
||||||
|
// 'shaderId' is the id of a <script> element containing the shader source string.
|
||||||
|
// Load this shader and return the WebGLShader object corresponding to it.
|
||||||
|
//
|
||||||
|
function loadShader(ctx, shaderId)
|
||||||
|
{
|
||||||
|
var shaderScript = document.getElementById(shaderId);
|
||||||
|
if (!shaderScript) {
|
||||||
|
log("*** Error: shader script '"+shaderId+"' not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shaderScript.type == "x-shader/x-vertex")
|
||||||
|
var shaderType = ctx.VERTEX_SHADER;
|
||||||
|
else if (shaderScript.type == "x-shader/x-fragment")
|
||||||
|
var shaderType = ctx.FRAGMENT_SHADER;
|
||||||
|
else {
|
||||||
|
log("*** Error: shader script '"+shaderId+"' of undefined type '"+shaderScript.type+"'");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the shader object
|
||||||
|
var shader = ctx.createShader(shaderType);
|
||||||
|
|
||||||
|
// Load the shader source
|
||||||
|
ctx.shaderSource(shader, shaderScript.text);
|
||||||
|
|
||||||
|
// Compile the shader
|
||||||
|
ctx.compileShader(shader);
|
||||||
|
|
||||||
|
// Check the compile status
|
||||||
|
var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
|
||||||
|
if (!compiled && !ctx.isContextLost()) {
|
||||||
|
// Something went wrong during compilation; get the error
|
||||||
|
var error = ctx.getShaderInfoLog(shader);
|
||||||
|
log("*** Error compiling shader '"+shaderId+"':"+error);
|
||||||
|
ctx.deleteShader(shader);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// makeBox
|
||||||
|
//
|
||||||
|
// Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
|
||||||
|
// Return an object with the following properties:
|
||||||
|
//
|
||||||
|
// normalObject WebGLBuffer object for normals
|
||||||
|
// texCoordObject WebGLBuffer object for texCoords
|
||||||
|
// vertexObject WebGLBuffer object for vertices
|
||||||
|
// indexObject WebGLBuffer object for indices
|
||||||
|
// numIndices The number of indices in the indexObject
|
||||||
|
//
|
||||||
|
function makeBox(ctx)
|
||||||
|
{
|
||||||
|
// box
|
||||||
|
// v6----- v5
|
||||||
|
// /| /|
|
||||||
|
// v1------v0|
|
||||||
|
// | | | |
|
||||||
|
// | |v7---|-|v4
|
||||||
|
// |/ |/
|
||||||
|
// v2------v3
|
||||||
|
//
|
||||||
|
// vertex coords array
|
||||||
|
var vertices = new Float32Array(
|
||||||
|
[ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0-v1-v2-v3 front
|
||||||
|
1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0-v3-v4-v5 right
|
||||||
|
1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0-v5-v6-v1 top
|
||||||
|
-1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1-v6-v7-v2 left
|
||||||
|
-1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7-v4-v3-v2 bottom
|
||||||
|
1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 ] // v4-v7-v6-v5 back
|
||||||
|
);
|
||||||
|
|
||||||
|
// normal array
|
||||||
|
var normals = new Float32Array(
|
||||||
|
[ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front
|
||||||
|
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
|
||||||
|
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top
|
||||||
|
-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left
|
||||||
|
0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3-v2 bottom
|
||||||
|
0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 ] // v4-v7-v6-v5 back
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// texCoord array
|
||||||
|
var texCoords = new Float32Array(
|
||||||
|
[ 1, 1, 0, 1, 0, 0, 1, 0, // v0-v1-v2-v3 front
|
||||||
|
0, 1, 0, 0, 1, 0, 1, 1, // v0-v3-v4-v5 right
|
||||||
|
1, 0, 1, 1, 0, 1, 0, 0, // v0-v5-v6-v1 top
|
||||||
|
1, 1, 0, 1, 0, 0, 1, 0, // v1-v6-v7-v2 left
|
||||||
|
0, 0, 1, 0, 1, 1, 0, 1, // v7-v4-v3-v2 bottom
|
||||||
|
0, 0, 1, 0, 1, 1, 0, 1 ] // v4-v7-v6-v5 back
|
||||||
|
);
|
||||||
|
|
||||||
|
// index array
|
||||||
|
var indices = new Uint8Array(
|
||||||
|
[ 0, 1, 2, 0, 2, 3, // front
|
||||||
|
4, 5, 6, 4, 6, 7, // right
|
||||||
|
8, 9,10, 8,10,11, // top
|
||||||
|
12,13,14, 12,14,15, // left
|
||||||
|
16,17,18, 16,18,19, // bottom
|
||||||
|
20,21,22, 20,22,23 ] // back
|
||||||
|
);
|
||||||
|
|
||||||
|
var retval = { };
|
||||||
|
|
||||||
|
retval.normalObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.texCoordObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.vertexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
|
||||||
|
|
||||||
|
retval.indexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
|
||||||
|
ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
|
||||||
|
|
||||||
|
retval.numIndices = indices.length;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// makeSphere
|
||||||
|
//
|
||||||
|
// Create a sphere with the passed number of latitude and longitude bands and the passed radius.
|
||||||
|
// Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
|
||||||
|
// Return an object with the following properties:
|
||||||
|
//
|
||||||
|
// normalObject WebGLBuffer object for normals
|
||||||
|
// texCoordObject WebGLBuffer object for texCoords
|
||||||
|
// vertexObject WebGLBuffer object for vertices
|
||||||
|
// indexObject WebGLBuffer object for indices
|
||||||
|
// numIndices The number of indices in the indexObject
|
||||||
|
//
|
||||||
|
function makeSphere(ctx, radius, lats, longs)
|
||||||
|
{
|
||||||
|
var geometryData = [ ];
|
||||||
|
var normalData = [ ];
|
||||||
|
var texCoordData = [ ];
|
||||||
|
var indexData = [ ];
|
||||||
|
|
||||||
|
for (var latNumber = 0; latNumber <= lats; ++latNumber) {
|
||||||
|
for (var longNumber = 0; longNumber <= longs; ++longNumber) {
|
||||||
|
var theta = latNumber * Math.PI / lats;
|
||||||
|
var phi = longNumber * 2 * Math.PI / longs;
|
||||||
|
var sinTheta = Math.sin(theta);
|
||||||
|
var sinPhi = Math.sin(phi);
|
||||||
|
var cosTheta = Math.cos(theta);
|
||||||
|
var cosPhi = Math.cos(phi);
|
||||||
|
|
||||||
|
var x = cosPhi * sinTheta;
|
||||||
|
var y = cosTheta;
|
||||||
|
var z = sinPhi * sinTheta;
|
||||||
|
var u = 1-(longNumber/longs);
|
||||||
|
var v = latNumber/lats;
|
||||||
|
|
||||||
|
normalData.push(x);
|
||||||
|
normalData.push(y);
|
||||||
|
normalData.push(z);
|
||||||
|
texCoordData.push(u);
|
||||||
|
texCoordData.push(v);
|
||||||
|
geometryData.push(radius * x);
|
||||||
|
geometryData.push(radius * y);
|
||||||
|
geometryData.push(radius * z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var latNumber = 0; latNumber < lats; ++latNumber) {
|
||||||
|
for (var longNumber = 0; longNumber < longs; ++longNumber) {
|
||||||
|
var first = (latNumber * (longs+1)) + longNumber;
|
||||||
|
var second = first + longs + 1;
|
||||||
|
indexData.push(first);
|
||||||
|
indexData.push(second);
|
||||||
|
indexData.push(first+1);
|
||||||
|
|
||||||
|
indexData.push(second);
|
||||||
|
indexData.push(second+1);
|
||||||
|
indexData.push(first+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var retval = { };
|
||||||
|
|
||||||
|
retval.normalObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.texCoordObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.vertexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.numIndices = indexData.length;
|
||||||
|
retval.indexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
|
||||||
|
ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of Objects curently loading
|
||||||
|
var g_loadingObjects = [];
|
||||||
|
|
||||||
|
// Clears all the Objects currently loading.
|
||||||
|
// This is used to handle context lost events.
|
||||||
|
function clearLoadingObjects() {
|
||||||
|
for (var ii = 0; ii < g_loadingObjects.length; ++ii) {
|
||||||
|
g_loadingObjects[ii].onreadystatechange = undefined;
|
||||||
|
}
|
||||||
|
g_loadingObjects = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// loadObj
|
||||||
|
//
|
||||||
|
// Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
|
||||||
|
// When the object load is complete, the 'loaded' property becomes true and the following
|
||||||
|
// properties are set:
|
||||||
|
//
|
||||||
|
// normalObject WebGLBuffer object for normals
|
||||||
|
// texCoordObject WebGLBuffer object for texCoords
|
||||||
|
// vertexObject WebGLBuffer object for vertices
|
||||||
|
// indexObject WebGLBuffer object for indices
|
||||||
|
// numIndices The number of indices in the indexObject
|
||||||
|
//
|
||||||
|
function loadObj(ctx, url)
|
||||||
|
{
|
||||||
|
var obj = { loaded : false };
|
||||||
|
obj.ctx = ctx;
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
req.obj = obj;
|
||||||
|
g_loadingObjects.push(req);
|
||||||
|
req.onreadystatechange = function () { processLoadObj(req) };
|
||||||
|
req.open("GET", url, true);
|
||||||
|
req.send(null);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processLoadObj(req)
|
||||||
|
{
|
||||||
|
log("req="+req)
|
||||||
|
// only if req shows "complete"
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
g_loadingObjects.splice(g_loadingObjects.indexOf(req), 1);
|
||||||
|
doLoadObj(req.obj, req.responseText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doLoadObj(obj, text)
|
||||||
|
{
|
||||||
|
vertexArray = [ ];
|
||||||
|
normalArray = [ ];
|
||||||
|
textureArray = [ ];
|
||||||
|
indexArray = [ ];
|
||||||
|
|
||||||
|
var vertex = [ ];
|
||||||
|
var normal = [ ];
|
||||||
|
var texture = [ ];
|
||||||
|
var facemap = { };
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
// This is a map which associates a range of indices with a name
|
||||||
|
// The name comes from the 'g' tag (of the form "g NAME"). Indices
|
||||||
|
// are part of one group until another 'g' tag is seen. If any indices
|
||||||
|
// come before a 'g' tag, it is given the group name "_unnamed"
|
||||||
|
// 'group' is an object whose property names are the group name and
|
||||||
|
// whose value is a 2 element array with [<first index>, <num indices>]
|
||||||
|
var groups = { };
|
||||||
|
var currentGroup = [-1, 0];
|
||||||
|
groups["_unnamed"] = currentGroup;
|
||||||
|
|
||||||
|
var lines = text.split("\n");
|
||||||
|
for (var lineIndex in lines) {
|
||||||
|
var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
|
||||||
|
|
||||||
|
// ignore comments
|
||||||
|
if (line[0] == "#")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var array = line.split(" ");
|
||||||
|
if (array[0] == "g") {
|
||||||
|
// new group
|
||||||
|
currentGroup = [indexArray.length, 0];
|
||||||
|
groups[array[1]] = currentGroup;
|
||||||
|
}
|
||||||
|
else if (array[0] == "v") {
|
||||||
|
// vertex
|
||||||
|
vertex.push(parseFloat(array[1]));
|
||||||
|
vertex.push(parseFloat(array[2]));
|
||||||
|
vertex.push(parseFloat(array[3]));
|
||||||
|
}
|
||||||
|
else if (array[0] == "vt") {
|
||||||
|
// normal
|
||||||
|
texture.push(parseFloat(array[1]));
|
||||||
|
texture.push(parseFloat(array[2]));
|
||||||
|
}
|
||||||
|
else if (array[0] == "vn") {
|
||||||
|
// normal
|
||||||
|
normal.push(parseFloat(array[1]));
|
||||||
|
normal.push(parseFloat(array[2]));
|
||||||
|
normal.push(parseFloat(array[3]));
|
||||||
|
}
|
||||||
|
else if (array[0] == "f") {
|
||||||
|
// face
|
||||||
|
if (array.length != 4) {
|
||||||
|
log("*** Error: face '"+line+"' not handled");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 1; i < 4; ++i) {
|
||||||
|
if (!(array[i] in facemap)) {
|
||||||
|
// add a new entry to the map and arrays
|
||||||
|
var f = array[i].split("/");
|
||||||
|
var vtx, nor, tex;
|
||||||
|
|
||||||
|
if (f.length == 1) {
|
||||||
|
vtx = parseInt(f[0]) - 1;
|
||||||
|
nor = vtx;
|
||||||
|
tex = vtx;
|
||||||
|
}
|
||||||
|
else if (f.length = 3) {
|
||||||
|
vtx = parseInt(f[0]) - 1;
|
||||||
|
tex = parseInt(f[1]) - 1;
|
||||||
|
nor = parseInt(f[2]) - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
obj.ctx.console.log("*** Error: did not understand face '"+array[i]+"'");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the vertices
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
var z = 0;
|
||||||
|
if (vtx * 3 + 2 < vertex.length) {
|
||||||
|
x = vertex[vtx*3];
|
||||||
|
y = vertex[vtx*3+1];
|
||||||
|
z = vertex[vtx*3+2];
|
||||||
|
}
|
||||||
|
vertexArray.push(x);
|
||||||
|
vertexArray.push(y);
|
||||||
|
vertexArray.push(z);
|
||||||
|
|
||||||
|
// do the textures
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
if (tex * 2 + 1 < texture.length) {
|
||||||
|
x = texture[tex*2];
|
||||||
|
y = texture[tex*2+1];
|
||||||
|
}
|
||||||
|
textureArray.push(x);
|
||||||
|
textureArray.push(y);
|
||||||
|
|
||||||
|
// do the normals
|
||||||
|
x = 0;
|
||||||
|
y = 0;
|
||||||
|
z = 1;
|
||||||
|
if (nor * 3 + 2 < normal.length) {
|
||||||
|
x = normal[nor*3];
|
||||||
|
y = normal[nor*3+1];
|
||||||
|
z = normal[nor*3+2];
|
||||||
|
}
|
||||||
|
normalArray.push(x);
|
||||||
|
normalArray.push(y);
|
||||||
|
normalArray.push(z);
|
||||||
|
|
||||||
|
facemap[array[i]] = index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexArray.push(facemap[array[i]]);
|
||||||
|
currentGroup[1]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the VBOs
|
||||||
|
obj.normalObject = obj.ctx.createBuffer();
|
||||||
|
obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
|
||||||
|
obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
obj.texCoordObject = obj.ctx.createBuffer();
|
||||||
|
obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
|
||||||
|
obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
obj.vertexObject = obj.ctx.createBuffer();
|
||||||
|
obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
|
||||||
|
obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
obj.numIndices = indexArray.length;
|
||||||
|
obj.indexObject = obj.ctx.createBuffer();
|
||||||
|
obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
|
||||||
|
obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW);
|
||||||
|
|
||||||
|
obj.groups = groups;
|
||||||
|
|
||||||
|
obj.loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array of images curently loading
|
||||||
|
var g_loadingImages = [];
|
||||||
|
|
||||||
|
// Clears all the images currently loading.
|
||||||
|
// This is used to handle context lost events.
|
||||||
|
function clearLoadingImages() {
|
||||||
|
for (var ii = 0; ii < g_loadingImages.length; ++ii) {
|
||||||
|
g_loadingImages[ii].onload = undefined;
|
||||||
|
}
|
||||||
|
g_loadingImages = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// loadImageTexture
|
||||||
|
//
|
||||||
|
// Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
|
||||||
|
//
|
||||||
|
function loadImageTexture(ctx, url)
|
||||||
|
{
|
||||||
|
var texture = ctx.createTexture();
|
||||||
|
var image = new Image();
|
||||||
|
g_loadingImages.push(image);
|
||||||
|
image.onload = function() { doLoadImageTexture(ctx, image, texture) }
|
||||||
|
image.src = url;
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doLoadImageTexture(ctx, image, texture)
|
||||||
|
{
|
||||||
|
g_loadingImages.splice(g_loadingImages.indexOf(image), 1);
|
||||||
|
ctx.bindTexture(ctx.TEXTURE_2D, texture);
|
||||||
|
ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
|
||||||
|
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
|
||||||
|
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR);
|
||||||
|
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
|
||||||
|
ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
|
||||||
|
//ctx.generateMipmap(ctx.TEXTURE_2D)
|
||||||
|
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Framerate object
|
||||||
|
//
|
||||||
|
// This object keeps track of framerate and displays it as the innerHTML text of the
|
||||||
|
// HTML element with the passed id. Once created you call snapshot at the end
|
||||||
|
// of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
|
||||||
|
//
|
||||||
|
Framerate = function(id)
|
||||||
|
{
|
||||||
|
this.numFramerates = 10;
|
||||||
|
this.framerateUpdateInterval = 500;
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.renderTime = -1;
|
||||||
|
this.framerates = [ ];
|
||||||
|
self = this;
|
||||||
|
var fr = function() { self.updateFramerate() }
|
||||||
|
setInterval(fr, this.framerateUpdateInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
Framerate.prototype.updateFramerate = function()
|
||||||
|
{
|
||||||
|
var tot = 0;
|
||||||
|
for (var i = 0; i < this.framerates.length; ++i)
|
||||||
|
tot += this.framerates[i];
|
||||||
|
|
||||||
|
var framerate = tot / this.framerates.length;
|
||||||
|
framerate = Math.round(framerate);
|
||||||
|
document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
|
||||||
|
}
|
||||||
|
|
||||||
|
Framerate.prototype.snapshot = function()
|
||||||
|
{
|
||||||
|
if (this.renderTime < 0)
|
||||||
|
this.renderTime = new Date().getTime();
|
||||||
|
else {
|
||||||
|
var newTime = new Date().getTime();
|
||||||
|
var t = newTime - this.renderTime;
|
||||||
|
if (t == 0)
|
||||||
|
return;
|
||||||
|
var framerate = 1000/t;
|
||||||
|
this.framerates.push(framerate);
|
||||||
|
while (this.framerates.length > this.numFramerates)
|
||||||
|
this.framerates.shift();
|
||||||
|
this.renderTime = newTime;
|
||||||
|
}
|
||||||
|
}
|
1065
J3DIMath.js
Normal file
1065
J3DIMath.js
Normal file
File diff suppressed because it is too large
Load diff
70
index.html
Normal file
70
index.html
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<title>TP - WebGL</title>
|
||||||
|
<link rel="stylesheet" href="tp.css" type="text/css" media="all">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="webgl-utils.js"></script>
|
||||||
|
<script type="text/javascript" src="webgl-debug.js"></script>
|
||||||
|
<script type="text/javascript" src="J3DI.js"></script>
|
||||||
|
<script type="text/javascript" src="J3DIMath.js"></script>
|
||||||
|
<script type="text/javascript" src="main.js"></script>
|
||||||
|
|
||||||
|
<script id="nuanceurSommets" type="x-shader/x-vertex">
|
||||||
|
uniform mat4 u_modelViewProjMatrix;
|
||||||
|
uniform mat4 u_normalMatrix;
|
||||||
|
uniform vec3 lightDir;
|
||||||
|
|
||||||
|
attribute vec4 vPosition;
|
||||||
|
attribute vec4 vColor;
|
||||||
|
|
||||||
|
varying float v_NdotL;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// assigner la position du sommet
|
||||||
|
gl_Position = u_modelViewProjMatrix * vPosition;
|
||||||
|
|
||||||
|
// assigner les coordonnées de texture
|
||||||
|
v_color = vColor;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="nuanceurFragments" type="x-shader/x-fragment">
|
||||||
|
// informer du degré de précision qu'on veut dans les calculs
|
||||||
|
// (Plus à ce sujet: http://stackoverflow.com/questions/5366416/in-opengl-es-2-0-glsl-where-do-you-need-precision-specifiers/6336285#6336285 )
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D laTexture;
|
||||||
|
uniform vec2 positionSouris;
|
||||||
|
|
||||||
|
varying float v_NdotL;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// obtenir la couleur de la texture
|
||||||
|
vec4 coul = v_color;
|
||||||
|
if ( length( positionSouris - gl_FragCoord.xy ) < 50.0 )
|
||||||
|
{
|
||||||
|
vec4 coulCercle = vec4( 1.0, 0.0, 0.0, 0.7 );
|
||||||
|
coul = coul * (1.0-coulCercle.a) + coulCercle * coulCercle.a;
|
||||||
|
// coul = coul * coulCercle; // réponse aussi acceptée
|
||||||
|
}
|
||||||
|
gl_FragColor = vec4( coul.rgb, coul.a );
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="TPdebut()">
|
||||||
|
<canvas class="canevas" id="tp-canevas" height="600" width="900">
|
||||||
|
Si vous voyez ceci, votre navigateur ne supporte pas webgl.
|
||||||
|
</canvas>
|
||||||
|
|
||||||
|
<div class="text">Les <a href="http://www.khronos.org/registry/webgl/specs/latest/1.0/">spécifications de Webgl</a> sont<br>remplies d'informations intéressantes.</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
254
main.js
Normal file
254
main.js
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
// Prénoms, noms et matricule des membres de l'équipe:
|
||||||
|
// - Prénom1 NOM1 (matricule1)
|
||||||
|
// - Prénom2 NOM2 (matricule2)
|
||||||
|
|
||||||
|
|
||||||
|
// déclaration d'une structure pour contenir toutes les variables globales
|
||||||
|
var glob = { };
|
||||||
|
|
||||||
|
function handleMouseDown(event)
|
||||||
|
{
|
||||||
|
glob.mouseDown = true;
|
||||||
|
glob.positionSourisX = event.clientX-15;
|
||||||
|
glob.positionSourisY = event.clientY-15;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseUp(event)
|
||||||
|
{
|
||||||
|
glob.mouseDown = false;
|
||||||
|
glob.positionSourisX = null;
|
||||||
|
glob.positionSourisY = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseMove(event)
|
||||||
|
{
|
||||||
|
if (!glob.mouseDown) return;
|
||||||
|
glob.positionSourisX = event.clientX-15;
|
||||||
|
glob.positionSourisY = event.clientY-15;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// makeRepere
|
||||||
|
//
|
||||||
|
// Create a repere with vertices, normals and texCoords. Create VBOs for each as well as the index array.
|
||||||
|
// Return an object with the following properties:
|
||||||
|
//
|
||||||
|
// normalObject WebGLBuffer object for normals
|
||||||
|
// texCoordObject WebGLBuffer object for texCoords
|
||||||
|
// vertexObject WebGLBuffer object for vertices
|
||||||
|
// indexObject WebGLBuffer object for indices
|
||||||
|
// numIndices The number of indices in the indexObject
|
||||||
|
//
|
||||||
|
function makeRepere(ctx)
|
||||||
|
{
|
||||||
|
// box
|
||||||
|
// v2
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// v0 o------v1
|
||||||
|
// /
|
||||||
|
// v3
|
||||||
|
//
|
||||||
|
// vertex coords array
|
||||||
|
var vertices = new Float32Array(
|
||||||
|
[ 0, 0, 0, 1, 0, 0, // v0 -> v1 vec X
|
||||||
|
0, 0, 0, 0, 1, 0, // v0 -> v2 vec Y
|
||||||
|
0, 0, 0, 0, 0, 1 ]// v0 -> v3 vec Z
|
||||||
|
);
|
||||||
|
|
||||||
|
// colors array
|
||||||
|
var colors = new Float32Array(
|
||||||
|
[ 1, 0, 0, 1, 0, 0, // v0 -> v1 vec X
|
||||||
|
0, 1, 0, 0, 1, 0, // v0 -> v2 vec Y
|
||||||
|
0, 0, 1, 0, 0, 1 ]// v0 -> v3 vec Z
|
||||||
|
);
|
||||||
|
|
||||||
|
// index array
|
||||||
|
var indices = new Uint8Array(
|
||||||
|
[ 0, 1,
|
||||||
|
2, 3,
|
||||||
|
4, 5 ]
|
||||||
|
);
|
||||||
|
|
||||||
|
var retval = { };
|
||||||
|
|
||||||
|
retval.vertexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
retval.colorObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.colorObject);
|
||||||
|
ctx.bufferData(ctx.ARRAY_BUFFER, colors, ctx.STATIC_DRAW);
|
||||||
|
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
|
||||||
|
|
||||||
|
retval.indexObject = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
|
||||||
|
ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
|
||||||
|
|
||||||
|
retval.numIndices = indices.length;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
function TPchargerTextures()
|
||||||
|
{
|
||||||
|
// Charger une image utilisée comme texture. (Retourne un objet WebGLTexture)
|
||||||
|
glob.texture1 = loadImageTexture( gl, "images/Brouillard.jpg" );
|
||||||
|
glob.texture2 = loadImageTexture( gl, "images/Exploration.jpg" );
|
||||||
|
//glob.texture3 = loadImageTexture( gl, "images/Modelisation.jpg" );
|
||||||
|
}
|
||||||
|
|
||||||
|
function TPcreerModele()
|
||||||
|
{
|
||||||
|
// Créer une boîte. Au retour, 'glob.box' contient une structure avec
|
||||||
|
// les VBOs pour les sommets, normales, coordonnées de texture et connectivité.
|
||||||
|
glob.box = makeRepere( gl );
|
||||||
|
|
||||||
|
// Initialiser les attributs pour les sommets, les normales et les coordonnées de texture
|
||||||
|
// (dans le même ordre qu'à l'appel à simpleSetup() dans la fonction TPinitialiser())
|
||||||
|
gl.enableVertexAttribArray( 0 );
|
||||||
|
gl.bindBuffer( gl.ARRAY_BUFFER, glob.box.vertexObject );
|
||||||
|
gl.vertexAttribPointer( 0, 3, gl.FLOAT, false, 0, 0 );
|
||||||
|
|
||||||
|
gl.enableVertexAttribArray( 1 );
|
||||||
|
gl.bindBuffer( gl.ARRAY_BUFFER, glob.box.colorObject );
|
||||||
|
gl.vertexAttribPointer( 1, 3, gl.FLOAT, false, 0, 0 );
|
||||||
|
|
||||||
|
// Lier le tableau de connectivité
|
||||||
|
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, glob.box.indexObject );
|
||||||
|
}
|
||||||
|
|
||||||
|
function TPinitialiser()
|
||||||
|
{
|
||||||
|
// Initialiser webgl
|
||||||
|
var gl = initWebGL( "tp-canevas" ); // L'identificateur du canevas
|
||||||
|
if (!gl) return;
|
||||||
|
|
||||||
|
glob.program = simpleSetup( gl,
|
||||||
|
// Les identificateurs des deux nuanceurs
|
||||||
|
"nuanceurSommets", "nuanceurFragments",
|
||||||
|
// Les attributs utilisés par les nuanceurs (donnés dans le même ordre que leur indice)
|
||||||
|
[ "vPosition", "vColor" ],
|
||||||
|
// La couleur de fond et la profondeur
|
||||||
|
[ 0, 0, 0.3, 1 ], 100);
|
||||||
|
|
||||||
|
// Les angles courants de rotation
|
||||||
|
glob.angleRotX = 0, glob.angleRotY = 0, glob.angleRotZ = 0;
|
||||||
|
// Les incréments à chaque affichage
|
||||||
|
glob.incrRotX = 0.2; glob.incrRotY = 0.3; glob.incrRotZ = 0.4;
|
||||||
|
|
||||||
|
// Créer les matrices nécessaires et assigner les assigner dans le programme
|
||||||
|
glob.modelViewMatrix = new J3DIMatrix4();
|
||||||
|
// glob.u_modelViewMatrixLoc n'est pas utile car modelViewMatrix n'est pas utilisé dans les nuanceurs
|
||||||
|
glob.mvpMatrix = new J3DIMatrix4();
|
||||||
|
glob.u_modelViewProjMatrixLoc = gl.getUniformLocation( glob.program, "u_modelViewProjMatrix" );
|
||||||
|
glob.normalMatrix = new J3DIMatrix4();
|
||||||
|
glob.u_normalMatrixLoc = gl.getUniformLocation( glob.program, "u_normalMatrix" );
|
||||||
|
|
||||||
|
// terminer l'initialisation
|
||||||
|
TPchargerTextures();
|
||||||
|
TPcreerModele();
|
||||||
|
|
||||||
|
glob.mouseDown = false;
|
||||||
|
glob.positionSourisX = null;
|
||||||
|
glob.positionSourisY = null;
|
||||||
|
glob.canevas.onmousedown = handleMouseDown;
|
||||||
|
glob.canevas.onmouseup = handleMouseUp;
|
||||||
|
glob.canevas.onmousemove = handleMouseMove;
|
||||||
|
|
||||||
|
// Initialiser les variables uniformes pour les nuanceurs
|
||||||
|
gl.uniform3f( gl.getUniformLocation( glob.program, "lightDir" ), 0, 0, 1 );
|
||||||
|
gl.uniform1i( gl.getUniformLocation( glob.program, "laTexture" ), 0 );
|
||||||
|
gl.uniform2f( gl.getUniformLocation( glob.program, "positionSouris" ), glob.positionSourisX, glob.positionSourisY );
|
||||||
|
|
||||||
|
return gl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TPafficherModele( gl, num )
|
||||||
|
{
|
||||||
|
// Incrémenter les angles de rotation
|
||||||
|
glob.angleRotX += glob.incrRotX; if ( glob.angleRotX >= 360.0 ) glob.angleRotX -= 360.0;
|
||||||
|
glob.angleRotY += glob.incrRotY; if ( glob.angleRotY >= 360.0 ) glob.angleRotY -= 360.0;
|
||||||
|
glob.angleRotZ += glob.incrRotZ; if ( glob.angleRotZ >= 360.0 ) glob.angleRotZ -= 360.0;
|
||||||
|
|
||||||
|
// Construire la matrice de modélisation
|
||||||
|
glob.modelViewMatrix.makeIdentity();
|
||||||
|
glob.modelViewMatrix.lookat( 0, 0, 7, 0, 0, 0, 0, 1, 0 );
|
||||||
|
var sens = ( num == 1 ) ? +1 : -1;
|
||||||
|
glob.modelViewMatrix.rotate( sens*glob.angleRotX, 1.0, 0.0, 0.0 );
|
||||||
|
glob.modelViewMatrix.rotate( sens*glob.angleRotY, 0.0, 1.0, 0.0 );
|
||||||
|
glob.modelViewMatrix.rotate( sens*glob.angleRotZ, 0.0, 0.0, 1.0 );
|
||||||
|
|
||||||
|
// Construire le produit de matrice "modélisation * projection" et la passer aux nuanceurs
|
||||||
|
glob.mvpMatrix.load( glob.perspectiveMatrix );
|
||||||
|
glob.mvpMatrix.multiply( glob.modelViewMatrix );
|
||||||
|
glob.mvpMatrix.setUniform( gl, glob.u_modelViewProjMatrixLoc, false );
|
||||||
|
|
||||||
|
// Construire la matrice de transformation des normales et la passer aux nuanceurs
|
||||||
|
glob.normalMatrix.load( glob.modelViewMatrix );
|
||||||
|
glob.normalMatrix.invert();
|
||||||
|
glob.normalMatrix.transpose();
|
||||||
|
glob.normalMatrix.setUniform( gl, glob.u_normalMatrixLoc, false );
|
||||||
|
|
||||||
|
// Activer la texture à utiliser
|
||||||
|
gl.bindTexture( gl.TEXTURE_2D, ( num == 1 ) ? glob.texture1 : glob.texture2 );
|
||||||
|
|
||||||
|
gl.uniform2f( gl.getUniformLocation( glob.program, "positionSouris" ), glob.positionSourisX, glob.canevas.height-glob.positionSourisY );
|
||||||
|
|
||||||
|
// Tracer le cube
|
||||||
|
gl.drawElements( gl.LINES, glob.box.numIndices, gl.UNSIGNED_BYTE, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
function TPafficherScene(gl)
|
||||||
|
{
|
||||||
|
glob.perspectiveMatrix = new J3DIMatrix4();
|
||||||
|
glob.perspectiveMatrix.perspective( 40, glob.canevas.width / glob.canevas.height, 1, 10 );
|
||||||
|
|
||||||
|
// Effacer le canevas
|
||||||
|
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
|
||||||
|
|
||||||
|
// Définir la clôture 1
|
||||||
|
gl.viewport( 0, 0, glob.canevas.width, glob.canevas.height );
|
||||||
|
// Tracer le modèle
|
||||||
|
TPafficherModele( gl, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestId;
|
||||||
|
function TPdebut()
|
||||||
|
{
|
||||||
|
glob.canevas = document.getElementById('tp-canevas');
|
||||||
|
//glob.canevas = WebGLDebugUtils.makeLostContextSimulatingCanvas(c);
|
||||||
|
// indiquer de perdre le contexte afin de tester
|
||||||
|
//glob.canevas.loseContextInNCalls(15);
|
||||||
|
glob.canevas.addEventListener('webglcontextlost', handleContextLost, false);
|
||||||
|
glob.canevas.addEventListener('webglcontextrestored', handleContextRestored, false);
|
||||||
|
|
||||||
|
var gl = TPinitialiser();
|
||||||
|
if ( !gl ) return;
|
||||||
|
|
||||||
|
var displayFunc = function()
|
||||||
|
{
|
||||||
|
TPafficherScene(gl);
|
||||||
|
requestId = window.requestAnimFrame( displayFunc, glob.canevas );
|
||||||
|
};
|
||||||
|
displayFunc();
|
||||||
|
|
||||||
|
function handleContextLost(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
clearLoadingImages();
|
||||||
|
if ( requestId !== undefined )
|
||||||
|
{
|
||||||
|
window.cancelAnimFrame(requestId);
|
||||||
|
requestId = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleContextRestored()
|
||||||
|
{
|
||||||
|
TPinitialiser();
|
||||||
|
displayFunc();
|
||||||
|
}
|
||||||
|
}
|
16
tp.css
Normal file
16
tp.css
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.text {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 20px;
|
||||||
|
font-size: 1em;
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link { color: yellow; }
|
||||||
|
a:hover { color: #bbaa00; }
|
||||||
|
|
||||||
|
.canevas {
|
||||||
|
height: 600px;
|
||||||
|
width: 900px;
|
||||||
|
border: 5px solid orange;
|
||||||
|
}
|
875
webgl-debug.js
Normal file
875
webgl-debug.js
Normal file
|
@ -0,0 +1,875 @@
|
||||||
|
/*
|
||||||
|
** Copyright (c) 2012 The Khronos Group Inc.
|
||||||
|
**
|
||||||
|
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
** copy of this software and/or associated documentation files (the
|
||||||
|
** "Materials"), to deal in the Materials without restriction, including
|
||||||
|
** without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||||
|
** permit persons to whom the Materials are 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 Materials.
|
||||||
|
**
|
||||||
|
** THE MATERIALS ARE 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
|
||||||
|
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Various functions for helping debug WebGL apps.
|
||||||
|
|
||||||
|
WebGLDebugUtils = function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapped logging function.
|
||||||
|
* @param {string} msg Message to log.
|
||||||
|
*/
|
||||||
|
var log = function(msg) {
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapped error logging function.
|
||||||
|
* @param {string} msg Message to log.
|
||||||
|
*/
|
||||||
|
var error = function(msg) {
|
||||||
|
if (window.console && window.console.error) {
|
||||||
|
window.console.error(msg);
|
||||||
|
} else {
|
||||||
|
log(msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which arguements are enums.
|
||||||
|
* @type {!Object.<number, string>}
|
||||||
|
*/
|
||||||
|
var glValidEnumContexts = {
|
||||||
|
|
||||||
|
// Generic setters and getters
|
||||||
|
|
||||||
|
'enable': { 0:true },
|
||||||
|
'disable': { 0:true },
|
||||||
|
'getParameter': { 0:true },
|
||||||
|
|
||||||
|
// Rendering
|
||||||
|
|
||||||
|
'drawArrays': { 0:true },
|
||||||
|
'drawElements': { 0:true, 2:true },
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
|
||||||
|
'createShader': { 0:true },
|
||||||
|
'getShaderParameter': { 1:true },
|
||||||
|
'getProgramParameter': { 1:true },
|
||||||
|
|
||||||
|
// Vertex attributes
|
||||||
|
|
||||||
|
'getVertexAttrib': { 1:true },
|
||||||
|
'vertexAttribPointer': { 2:true },
|
||||||
|
|
||||||
|
// Textures
|
||||||
|
|
||||||
|
'bindTexture': { 0:true },
|
||||||
|
'activeTexture': { 0:true },
|
||||||
|
'getTexParameter': { 0:true, 1:true },
|
||||||
|
'texParameterf': { 0:true, 1:true },
|
||||||
|
'texParameteri': { 0:true, 1:true, 2:true },
|
||||||
|
'texImage2D': { 0:true, 2:true, 6:true, 7:true },
|
||||||
|
'texSubImage2D': { 0:true, 6:true, 7:true },
|
||||||
|
'copyTexImage2D': { 0:true, 2:true },
|
||||||
|
'copyTexSubImage2D': { 0:true },
|
||||||
|
'generateMipmap': { 0:true },
|
||||||
|
|
||||||
|
// Buffer objects
|
||||||
|
|
||||||
|
'bindBuffer': { 0:true },
|
||||||
|
'bufferData': { 0:true, 2:true },
|
||||||
|
'bufferSubData': { 0:true },
|
||||||
|
'getBufferParameter': { 0:true, 1:true },
|
||||||
|
|
||||||
|
// Renderbuffers and framebuffers
|
||||||
|
|
||||||
|
'pixelStorei': { 0:true, 1:true },
|
||||||
|
'readPixels': { 4:true, 5:true },
|
||||||
|
'bindRenderbuffer': { 0:true },
|
||||||
|
'bindFramebuffer': { 0:true },
|
||||||
|
'checkFramebufferStatus': { 0:true },
|
||||||
|
'framebufferRenderbuffer': { 0:true, 1:true, 2:true },
|
||||||
|
'framebufferTexture2D': { 0:true, 1:true, 2:true },
|
||||||
|
'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true },
|
||||||
|
'getRenderbufferParameter': { 0:true, 1:true },
|
||||||
|
'renderbufferStorage': { 0:true, 1:true },
|
||||||
|
|
||||||
|
// Frame buffer operations (clear, blend, depth test, stencil)
|
||||||
|
|
||||||
|
'clear': { 0:true },
|
||||||
|
'depthFunc': { 0:true },
|
||||||
|
'blendFunc': { 0:true, 1:true },
|
||||||
|
'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true },
|
||||||
|
'blendEquation': { 0:true },
|
||||||
|
'blendEquationSeparate': { 0:true, 1:true },
|
||||||
|
'stencilFunc': { 0:true },
|
||||||
|
'stencilFuncSeparate': { 0:true, 1:true },
|
||||||
|
'stencilMaskSeparate': { 0:true },
|
||||||
|
'stencilOp': { 0:true, 1:true, 2:true },
|
||||||
|
'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true },
|
||||||
|
|
||||||
|
// Culling
|
||||||
|
|
||||||
|
'cullFace': { 0:true },
|
||||||
|
'frontFace': { 0:true },
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of numbers to names.
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
var glEnums = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this module. Safe to call more than once.
|
||||||
|
* @param {!WebGLRenderingContext} ctx A WebGL context. If
|
||||||
|
* you have more than one context it doesn't matter which one
|
||||||
|
* you pass in, it is only used to pull out constants.
|
||||||
|
*/
|
||||||
|
function init(ctx) {
|
||||||
|
if (glEnums == null) {
|
||||||
|
glEnums = { };
|
||||||
|
for (var propertyName in ctx) {
|
||||||
|
if (typeof ctx[propertyName] == 'number') {
|
||||||
|
glEnums[ctx[propertyName]] = propertyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the utils have been initialized.
|
||||||
|
*/
|
||||||
|
function checkInit() {
|
||||||
|
if (glEnums == null) {
|
||||||
|
throw 'WebGLDebugUtils.init(ctx) not called';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true or false if value matches any WebGL enum
|
||||||
|
* @param {*} value Value to check if it might be an enum.
|
||||||
|
* @return {boolean} True if value matches one of the WebGL defined enums
|
||||||
|
*/
|
||||||
|
function mightBeEnum(value) {
|
||||||
|
checkInit();
|
||||||
|
return (glEnums[value] !== undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an string version of an WebGL enum.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* var str = WebGLDebugUtil.glEnumToString(ctx.getError());
|
||||||
|
*
|
||||||
|
* @param {number} value Value to return an enum for
|
||||||
|
* @return {string} The string version of the enum.
|
||||||
|
*/
|
||||||
|
function glEnumToString(value) {
|
||||||
|
checkInit();
|
||||||
|
var name = glEnums[value];
|
||||||
|
return (name !== undefined) ? name :
|
||||||
|
("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string version of a WebGL argument.
|
||||||
|
* Attempts to convert enum arguments to strings.
|
||||||
|
* @param {string} functionName the name of the WebGL function.
|
||||||
|
* @param {number} argumentIndx the index of the argument.
|
||||||
|
* @param {*} value The value of the argument.
|
||||||
|
* @return {string} The value as a string.
|
||||||
|
*/
|
||||||
|
function glFunctionArgToString(functionName, argumentIndex, value) {
|
||||||
|
var funcInfo = glValidEnumContexts[functionName];
|
||||||
|
if (funcInfo !== undefined) {
|
||||||
|
if (funcInfo[argumentIndex]) {
|
||||||
|
return glEnumToString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value === null) {
|
||||||
|
return "null";
|
||||||
|
} else if (value === undefined) {
|
||||||
|
return "undefined";
|
||||||
|
} else {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the arguments of a WebGL function to a string.
|
||||||
|
* Attempts to convert enum arguments to strings.
|
||||||
|
*
|
||||||
|
* @param {string} functionName the name of the WebGL function.
|
||||||
|
* @param {number} args The arguments.
|
||||||
|
* @return {string} The arguments as a string.
|
||||||
|
*/
|
||||||
|
function glFunctionArgsToString(functionName, args) {
|
||||||
|
// apparently we can't do args.join(",");
|
||||||
|
var argStr = "";
|
||||||
|
for (var ii = 0; ii < args.length; ++ii) {
|
||||||
|
argStr += ((ii == 0) ? '' : ', ') +
|
||||||
|
glFunctionArgToString(functionName, ii, args[ii]);
|
||||||
|
}
|
||||||
|
return argStr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function makePropertyWrapper(wrapper, original, propertyName) {
|
||||||
|
//log("wrap prop: " + propertyName);
|
||||||
|
wrapper.__defineGetter__(propertyName, function() {
|
||||||
|
return original[propertyName];
|
||||||
|
});
|
||||||
|
// TODO(gmane): this needs to handle properties that take more than
|
||||||
|
// one value?
|
||||||
|
wrapper.__defineSetter__(propertyName, function(value) {
|
||||||
|
//log("set: " + propertyName);
|
||||||
|
original[propertyName] = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes a function that calls a function on another object.
|
||||||
|
function makeFunctionWrapper(original, functionName) {
|
||||||
|
//log("wrap fn: " + functionName);
|
||||||
|
var f = original[functionName];
|
||||||
|
return function() {
|
||||||
|
//log("call: " + functionName);
|
||||||
|
var result = f.apply(original, arguments);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a WebGL context returns a wrapped context that calls
|
||||||
|
* gl.getError after every command and calls a function if the
|
||||||
|
* result is not gl.NO_ERROR.
|
||||||
|
*
|
||||||
|
* @param {!WebGLRenderingContext} ctx The webgl context to
|
||||||
|
* wrap.
|
||||||
|
* @param {!function(err, funcName, args): void} opt_onErrorFunc
|
||||||
|
* The function to call when gl.getError returns an
|
||||||
|
* error. If not specified the default function calls
|
||||||
|
* console.log with a message.
|
||||||
|
* @param {!function(funcName, args): void} opt_onFunc The
|
||||||
|
* function to call when each webgl function is called.
|
||||||
|
* You can use this to log all calls for example.
|
||||||
|
*/
|
||||||
|
function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc) {
|
||||||
|
init(ctx);
|
||||||
|
opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
|
||||||
|
// apparently we can't do args.join(",");
|
||||||
|
var argStr = "";
|
||||||
|
for (var ii = 0; ii < args.length; ++ii) {
|
||||||
|
argStr += ((ii == 0) ? '' : ', ') +
|
||||||
|
glFunctionArgToString(functionName, ii, args[ii]);
|
||||||
|
}
|
||||||
|
error("WebGL error "+ glEnumToString(err) + " in "+ functionName +
|
||||||
|
"(" + argStr + ")");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Holds booleans for each GL error so after we get the error ourselves
|
||||||
|
// we can still return it to the client app.
|
||||||
|
var glErrorShadow = { };
|
||||||
|
|
||||||
|
// Makes a function that calls a WebGL function and then calls getError.
|
||||||
|
function makeErrorWrapper(ctx, functionName) {
|
||||||
|
return function() {
|
||||||
|
if (opt_onFunc) {
|
||||||
|
opt_onFunc(functionName, arguments);
|
||||||
|
}
|
||||||
|
var result = ctx[functionName].apply(ctx, arguments);
|
||||||
|
var err = ctx.getError();
|
||||||
|
if (err != 0) {
|
||||||
|
glErrorShadow[err] = true;
|
||||||
|
opt_onErrorFunc(err, functionName, arguments);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a an object that has a copy of every property of the WebGL context
|
||||||
|
// but wraps all functions.
|
||||||
|
var wrapper = {};
|
||||||
|
for (var propertyName in ctx) {
|
||||||
|
if (typeof ctx[propertyName] == 'function') {
|
||||||
|
wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
|
||||||
|
} else {
|
||||||
|
makePropertyWrapper(wrapper, ctx, propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override the getError function with one that returns our saved results.
|
||||||
|
wrapper.getError = function() {
|
||||||
|
for (var err in glErrorShadow) {
|
||||||
|
if (glErrorShadow.hasOwnProperty(err)) {
|
||||||
|
if (glErrorShadow[err]) {
|
||||||
|
glErrorShadow[err] = false;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.NO_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetToInitialState(ctx) {
|
||||||
|
var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
|
||||||
|
var tmp = ctx.createBuffer();
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp);
|
||||||
|
for (var ii = 0; ii < numAttribs; ++ii) {
|
||||||
|
ctx.disableVertexAttribArray(ii);
|
||||||
|
ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0);
|
||||||
|
ctx.vertexAttrib1f(ii, 0);
|
||||||
|
}
|
||||||
|
ctx.deleteBuffer(tmp);
|
||||||
|
|
||||||
|
var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
|
||||||
|
for (var ii = 0; ii < numTextureUnits; ++ii) {
|
||||||
|
ctx.activeTexture(ctx.TEXTURE0 + ii);
|
||||||
|
ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null);
|
||||||
|
ctx.bindTexture(ctx.TEXTURE_2D, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.activeTexture(ctx.TEXTURE0);
|
||||||
|
ctx.useProgram(null);
|
||||||
|
ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
|
||||||
|
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
|
||||||
|
ctx.bindFramebuffer(ctx.FRAMEBUFFER, null);
|
||||||
|
ctx.bindRenderbuffer(ctx.RENDERBUFFER, null);
|
||||||
|
ctx.disable(ctx.BLEND);
|
||||||
|
ctx.disable(ctx.CULL_FACE);
|
||||||
|
ctx.disable(ctx.DEPTH_TEST);
|
||||||
|
ctx.disable(ctx.DITHER);
|
||||||
|
ctx.disable(ctx.SCISSOR_TEST);
|
||||||
|
ctx.blendColor(0, 0, 0, 0);
|
||||||
|
ctx.blendEquation(ctx.FUNC_ADD);
|
||||||
|
ctx.blendFunc(ctx.ONE, ctx.ZERO);
|
||||||
|
ctx.clearColor(0, 0, 0, 0);
|
||||||
|
ctx.clearDepth(1);
|
||||||
|
ctx.clearStencil(-1);
|
||||||
|
ctx.colorMask(true, true, true, true);
|
||||||
|
ctx.cullFace(ctx.BACK);
|
||||||
|
ctx.depthFunc(ctx.LESS);
|
||||||
|
ctx.depthMask(true);
|
||||||
|
ctx.depthRange(0, 1);
|
||||||
|
ctx.frontFace(ctx.CCW);
|
||||||
|
ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE);
|
||||||
|
ctx.lineWidth(1);
|
||||||
|
ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4);
|
||||||
|
ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4);
|
||||||
|
ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false);
|
||||||
|
ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
||||||
|
// TODO: Delete this IF.
|
||||||
|
if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) {
|
||||||
|
ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL);
|
||||||
|
}
|
||||||
|
ctx.polygonOffset(0, 0);
|
||||||
|
ctx.sampleCoverage(1, false);
|
||||||
|
ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
|
ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF);
|
||||||
|
ctx.stencilMask(0xFFFFFFFF);
|
||||||
|
ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP);
|
||||||
|
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
|
||||||
|
ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
// TODO: This should NOT be needed but Firefox fails with 'hint'
|
||||||
|
while(ctx.getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeLostContextSimulatingCanvas(canvas) {
|
||||||
|
var unwrappedContext_;
|
||||||
|
var wrappedContext_;
|
||||||
|
var onLost_ = [];
|
||||||
|
var onRestored_ = [];
|
||||||
|
var wrappedContext_ = {};
|
||||||
|
var contextId_ = 1;
|
||||||
|
var contextLost_ = false;
|
||||||
|
var resourceId_ = 0;
|
||||||
|
var resourceDb_ = [];
|
||||||
|
var numCallsToLoseContext_ = 0;
|
||||||
|
var numCalls_ = 0;
|
||||||
|
var canRestore_ = false;
|
||||||
|
var restoreTimeout_ = 0;
|
||||||
|
|
||||||
|
// Holds booleans for each GL error so can simulate errors.
|
||||||
|
var glErrorShadow_ = { };
|
||||||
|
|
||||||
|
canvas.getContext = function(f) {
|
||||||
|
return function() {
|
||||||
|
var ctx = f.apply(canvas, arguments);
|
||||||
|
// Did we get a context and is it a WebGL context?
|
||||||
|
if (ctx instanceof WebGLRenderingContext) {
|
||||||
|
if (ctx != unwrappedContext_) {
|
||||||
|
if (unwrappedContext_) {
|
||||||
|
throw "got different context"
|
||||||
|
}
|
||||||
|
unwrappedContext_ = ctx;
|
||||||
|
wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_);
|
||||||
|
}
|
||||||
|
return wrappedContext_;
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
}(canvas.getContext);
|
||||||
|
|
||||||
|
function wrapEvent(listener) {
|
||||||
|
if (typeof(listener) == "function") {
|
||||||
|
return listener;
|
||||||
|
} else {
|
||||||
|
return function(info) {
|
||||||
|
listener.handleEvent(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var addOnContextLostListener = function(listener) {
|
||||||
|
onLost_.push(wrapEvent(listener));
|
||||||
|
};
|
||||||
|
|
||||||
|
var addOnContextRestoredListener = function(listener) {
|
||||||
|
onRestored_.push(wrapEvent(listener));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function wrapAddEventListener(canvas) {
|
||||||
|
var f = canvas.addEventListener;
|
||||||
|
canvas.addEventListener = function(type, listener, bubble) {
|
||||||
|
switch (type) {
|
||||||
|
case 'webglcontextlost':
|
||||||
|
addOnContextLostListener(listener);
|
||||||
|
break;
|
||||||
|
case 'webglcontextrestored':
|
||||||
|
addOnContextRestoredListener(listener);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f.apply(canvas, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapAddEventListener(canvas);
|
||||||
|
|
||||||
|
canvas.loseContext = function() {
|
||||||
|
if (!contextLost_) {
|
||||||
|
contextLost_ = true;
|
||||||
|
numCallsToLoseContext_ = 0;
|
||||||
|
++contextId_;
|
||||||
|
while (unwrappedContext_.getError());
|
||||||
|
clearErrors();
|
||||||
|
glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true;
|
||||||
|
var event = makeWebGLContextEvent("context lost");
|
||||||
|
var callbacks = onLost_.slice();
|
||||||
|
setTimeout(function() {
|
||||||
|
//log("numCallbacks:" + callbacks.length);
|
||||||
|
for (var ii = 0; ii < callbacks.length; ++ii) {
|
||||||
|
//log("calling callback:" + ii);
|
||||||
|
callbacks[ii](event);
|
||||||
|
}
|
||||||
|
if (restoreTimeout_ >= 0) {
|
||||||
|
setTimeout(function() {
|
||||||
|
canvas.restoreContext();
|
||||||
|
}, restoreTimeout_);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.restoreContext = function() {
|
||||||
|
if (contextLost_) {
|
||||||
|
if (onRestored_.length) {
|
||||||
|
setTimeout(function() {
|
||||||
|
if (!canRestore_) {
|
||||||
|
throw "can not restore. webglcontestlost listener did not call event.preventDefault";
|
||||||
|
}
|
||||||
|
freeResources();
|
||||||
|
resetToInitialState(unwrappedContext_);
|
||||||
|
contextLost_ = false;
|
||||||
|
numCalls_ = 0;
|
||||||
|
canRestore_ = false;
|
||||||
|
var callbacks = onRestored_.slice();
|
||||||
|
var event = makeWebGLContextEvent("context restored");
|
||||||
|
for (var ii = 0; ii < callbacks.length; ++ii) {
|
||||||
|
callbacks[ii](event);
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.loseContextInNCalls = function(numCalls) {
|
||||||
|
if (contextLost_) {
|
||||||
|
throw "You can not ask a lost contet to be lost";
|
||||||
|
}
|
||||||
|
numCallsToLoseContext_ = numCalls_ + numCalls;
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.getNumCalls = function() {
|
||||||
|
return numCalls_;
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.setRestoreTimeout = function(timeout) {
|
||||||
|
restoreTimeout_ = timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
function isWebGLObject(obj) {
|
||||||
|
//return false;
|
||||||
|
return (obj instanceof WebGLBuffer ||
|
||||||
|
obj instanceof WebGLFramebuffer ||
|
||||||
|
obj instanceof WebGLProgram ||
|
||||||
|
obj instanceof WebGLRenderbuffer ||
|
||||||
|
obj instanceof WebGLShader ||
|
||||||
|
obj instanceof WebGLTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkResources(args) {
|
||||||
|
for (var ii = 0; ii < args.length; ++ii) {
|
||||||
|
var arg = args[ii];
|
||||||
|
if (isWebGLObject(arg)) {
|
||||||
|
return arg.__webglDebugContextLostId__ == contextId_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearErrors() {
|
||||||
|
var k = Object.keys(glErrorShadow_);
|
||||||
|
for (var ii = 0; ii < k.length; ++ii) {
|
||||||
|
delete glErrorShadow_[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loseContextIfTime() {
|
||||||
|
++numCalls_;
|
||||||
|
if (!contextLost_) {
|
||||||
|
if (numCallsToLoseContext_ == numCalls_) {
|
||||||
|
canvas.loseContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Makes a function that simulates WebGL when out of context.
|
||||||
|
function makeLostContextFunctionWrapper(ctx, functionName) {
|
||||||
|
var f = ctx[functionName];
|
||||||
|
return function() {
|
||||||
|
// log("calling:" + functionName);
|
||||||
|
// Only call the functions if the context is not lost.
|
||||||
|
loseContextIfTime();
|
||||||
|
if (!contextLost_) {
|
||||||
|
//if (!checkResources(arguments)) {
|
||||||
|
// glErrorShadow_[wrappedContext_.INVALID_OPERATION] = true;
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
var result = f.apply(ctx, arguments);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function freeResources() {
|
||||||
|
for (var ii = 0; ii < resourceDb_.length; ++ii) {
|
||||||
|
var resource = resourceDb_[ii];
|
||||||
|
if (resource instanceof WebGLBuffer) {
|
||||||
|
unwrappedContext_.deleteBuffer(resource);
|
||||||
|
} else if (resource instanceof WebGLFramebuffer) {
|
||||||
|
unwrappedContext_.deleteFramebuffer(resource);
|
||||||
|
} else if (resource instanceof WebGLProgram) {
|
||||||
|
unwrappedContext_.deleteProgram(resource);
|
||||||
|
} else if (resource instanceof WebGLRenderbuffer) {
|
||||||
|
unwrappedContext_.deleteRenderbuffer(resource);
|
||||||
|
} else if (resource instanceof WebGLShader) {
|
||||||
|
unwrappedContext_.deleteShader(resource);
|
||||||
|
} else if (resource instanceof WebGLTexture) {
|
||||||
|
unwrappedContext_.deleteTexture(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeWebGLContextEvent(statusMessage) {
|
||||||
|
return {
|
||||||
|
statusMessage: statusMessage,
|
||||||
|
preventDefault: function() {
|
||||||
|
canRestore_ = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
|
||||||
|
function makeLostContextSimulatingContext(ctx) {
|
||||||
|
// copy all functions and properties to wrapper
|
||||||
|
for (var propertyName in ctx) {
|
||||||
|
if (typeof ctx[propertyName] == 'function') {
|
||||||
|
wrappedContext_[propertyName] = makeLostContextFunctionWrapper(
|
||||||
|
ctx, propertyName);
|
||||||
|
} else {
|
||||||
|
makePropertyWrapper(wrappedContext_, ctx, propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap a few functions specially.
|
||||||
|
wrappedContext_.getError = function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (!contextLost_) {
|
||||||
|
var err;
|
||||||
|
while (err = unwrappedContext_.getError()) {
|
||||||
|
glErrorShadow_[err] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var err in glErrorShadow_) {
|
||||||
|
if (glErrorShadow_[err]) {
|
||||||
|
delete glErrorShadow_[err];
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wrappedContext_.NO_ERROR;
|
||||||
|
};
|
||||||
|
|
||||||
|
var creationFunctions = [
|
||||||
|
"createBuffer",
|
||||||
|
"createFramebuffer",
|
||||||
|
"createProgram",
|
||||||
|
"createRenderbuffer",
|
||||||
|
"createShader",
|
||||||
|
"createTexture"
|
||||||
|
];
|
||||||
|
for (var ii = 0; ii < creationFunctions.length; ++ii) {
|
||||||
|
var functionName = creationFunctions[ii];
|
||||||
|
wrappedContext_[functionName] = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var obj = f.apply(ctx, arguments);
|
||||||
|
obj.__webglDebugContextLostId__ = contextId_;
|
||||||
|
resourceDb_.push(obj);
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
}(ctx[functionName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var functionsThatShouldReturnNull = [
|
||||||
|
"getActiveAttrib",
|
||||||
|
"getActiveUniform",
|
||||||
|
"getBufferParameter",
|
||||||
|
"getContextAttributes",
|
||||||
|
"getAttachedShaders",
|
||||||
|
"getFramebufferAttachmentParameter",
|
||||||
|
"getParameter",
|
||||||
|
"getProgramParameter",
|
||||||
|
"getProgramInfoLog",
|
||||||
|
"getRenderbufferParameter",
|
||||||
|
"getShaderParameter",
|
||||||
|
"getShaderInfoLog",
|
||||||
|
"getShaderSource",
|
||||||
|
"getTexParameter",
|
||||||
|
"getUniform",
|
||||||
|
"getUniformLocation",
|
||||||
|
"getVertexAttrib"
|
||||||
|
];
|
||||||
|
for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) {
|
||||||
|
var functionName = functionsThatShouldReturnNull[ii];
|
||||||
|
wrappedContext_[functionName] = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return f.apply(ctx, arguments);
|
||||||
|
}
|
||||||
|
}(wrappedContext_[functionName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var isFunctions = [
|
||||||
|
"isBuffer",
|
||||||
|
"isEnabled",
|
||||||
|
"isFramebuffer",
|
||||||
|
"isProgram",
|
||||||
|
"isRenderbuffer",
|
||||||
|
"isShader",
|
||||||
|
"isTexture"
|
||||||
|
];
|
||||||
|
for (var ii = 0; ii < isFunctions.length; ++ii) {
|
||||||
|
var functionName = isFunctions[ii];
|
||||||
|
wrappedContext_[functionName] = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return f.apply(ctx, arguments);
|
||||||
|
}
|
||||||
|
}(wrappedContext_[functionName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
wrappedContext_.checkFramebufferStatus = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return wrappedContext_.FRAMEBUFFER_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
return f.apply(ctx, arguments);
|
||||||
|
};
|
||||||
|
}(wrappedContext_.checkFramebufferStatus);
|
||||||
|
|
||||||
|
wrappedContext_.getAttribLocation = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return f.apply(ctx, arguments);
|
||||||
|
};
|
||||||
|
}(wrappedContext_.getAttribLocation);
|
||||||
|
|
||||||
|
wrappedContext_.getVertexAttribOffset = function(f) {
|
||||||
|
return function() {
|
||||||
|
loseContextIfTime();
|
||||||
|
if (contextLost_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return f.apply(ctx, arguments);
|
||||||
|
};
|
||||||
|
}(wrappedContext_.getVertexAttribOffset);
|
||||||
|
|
||||||
|
wrappedContext_.isContextLost = function() {
|
||||||
|
return contextLost_;
|
||||||
|
};
|
||||||
|
|
||||||
|
return wrappedContext_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* Initializes this module. Safe to call more than once.
|
||||||
|
* @param {!WebGLRenderingContext} ctx A WebGL context. If
|
||||||
|
}
|
||||||
|
* you have more than one context it doesn't matter which one
|
||||||
|
* you pass in, it is only used to pull out constants.
|
||||||
|
*/
|
||||||
|
'init': init,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true or false if value matches any WebGL enum
|
||||||
|
* @param {*} value Value to check if it might be an enum.
|
||||||
|
* @return {boolean} True if value matches one of the WebGL defined enums
|
||||||
|
*/
|
||||||
|
'mightBeEnum': mightBeEnum,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an string version of an WebGL enum.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* WebGLDebugUtil.init(ctx);
|
||||||
|
* var str = WebGLDebugUtil.glEnumToString(ctx.getError());
|
||||||
|
*
|
||||||
|
* @param {number} value Value to return an enum for
|
||||||
|
* @return {string} The string version of the enum.
|
||||||
|
*/
|
||||||
|
'glEnumToString': glEnumToString,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the argument of a WebGL function to a string.
|
||||||
|
* Attempts to convert enum arguments to strings.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* WebGLDebugUtil.init(ctx);
|
||||||
|
* var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D);
|
||||||
|
*
|
||||||
|
* would return 'TEXTURE_2D'
|
||||||
|
*
|
||||||
|
* @param {string} functionName the name of the WebGL function.
|
||||||
|
* @param {number} argumentIndx the index of the argument.
|
||||||
|
* @param {*} value The value of the argument.
|
||||||
|
* @return {string} The value as a string.
|
||||||
|
*/
|
||||||
|
'glFunctionArgToString': glFunctionArgToString,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the arguments of a WebGL function to a string.
|
||||||
|
* Attempts to convert enum arguments to strings.
|
||||||
|
*
|
||||||
|
* @param {string} functionName the name of the WebGL function.
|
||||||
|
* @param {number} args The arguments.
|
||||||
|
* @return {string} The arguments as a string.
|
||||||
|
*/
|
||||||
|
'glFunctionArgsToString': glFunctionArgsToString,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a WebGL context returns a wrapped context that calls
|
||||||
|
* gl.getError after every command and calls a function if the
|
||||||
|
* result is not NO_ERROR.
|
||||||
|
*
|
||||||
|
* You can supply your own function if you want. For example, if you'd like
|
||||||
|
* an exception thrown on any GL error you could do this
|
||||||
|
*
|
||||||
|
* function throwOnGLError(err, funcName, args) {
|
||||||
|
* throw WebGLDebugUtils.glEnumToString(err) +
|
||||||
|
* " was caused by call to " + funcName;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* ctx = WebGLDebugUtils.makeDebugContext(
|
||||||
|
* canvas.getContext("webgl"), throwOnGLError);
|
||||||
|
*
|
||||||
|
* @param {!WebGLRenderingContext} ctx The webgl context to wrap.
|
||||||
|
* @param {!function(err, funcName, args): void} opt_onErrorFunc The function
|
||||||
|
* to call when gl.getError returns an error. If not specified the default
|
||||||
|
* function calls console.log with a message.
|
||||||
|
* @param {!function(funcName, args): void} opt_onFunc The
|
||||||
|
* function to call when each webgl function is called. You
|
||||||
|
* can use this to log all calls for example.
|
||||||
|
*/
|
||||||
|
'makeDebugContext': makeDebugContext,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a canvas element returns a wrapped canvas element that will
|
||||||
|
* simulate lost context. The canvas returned adds the following functions.
|
||||||
|
*
|
||||||
|
* loseContext:
|
||||||
|
* simulates a lost context event.
|
||||||
|
*
|
||||||
|
* restoreContext:
|
||||||
|
* simulates the context being restored.
|
||||||
|
*
|
||||||
|
* lostContextInNCalls:
|
||||||
|
* loses the context after N gl calls.
|
||||||
|
*
|
||||||
|
* getNumCalls:
|
||||||
|
* tells you how many gl calls there have been so far.
|
||||||
|
*
|
||||||
|
* setRestoreTimeout:
|
||||||
|
* sets the number of milliseconds until the context is restored
|
||||||
|
* after it has been lost. Defaults to 0. Pass -1 to prevent
|
||||||
|
* automatic restoring.
|
||||||
|
*
|
||||||
|
* @param {!Canvas} canvas The canvas element to wrap.
|
||||||
|
*/
|
||||||
|
'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets a context to the initial state.
|
||||||
|
* @param {!WebGLRenderingContext} ctx The webgl context to
|
||||||
|
* reset.
|
||||||
|
*/
|
||||||
|
'resetToInitialState': resetToInitialState
|
||||||
|
};
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
176
webgl-utils.js
Normal file
176
webgl-utils.js
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010, Google Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following disclaimer
|
||||||
|
* in the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name of Google Inc. nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview This file contains functions every webgl program will need
|
||||||
|
* a version of one way or another.
|
||||||
|
*
|
||||||
|
* Instead of setting up a context manually it is recommended to
|
||||||
|
* use. This will check for success or failure. On failure it
|
||||||
|
* will attempt to present an approriate message to the user.
|
||||||
|
*
|
||||||
|
* gl = WebGLUtils.setupWebGL(canvas);
|
||||||
|
*
|
||||||
|
* For animated WebGL apps use of setTimeout or setInterval are
|
||||||
|
* discouraged. It is recommended you structure your rendering
|
||||||
|
* loop like this.
|
||||||
|
*
|
||||||
|
* function render() {
|
||||||
|
* window.requestAnimFrame(render, canvas);
|
||||||
|
*
|
||||||
|
* // do rendering
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* render();
|
||||||
|
*
|
||||||
|
* This will call your rendering function up to the refresh rate
|
||||||
|
* of your display but will stop rendering if your app is not
|
||||||
|
* visible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
WebGLUtils = function() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 '' +
|
||||||
|
'<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
|
||||||
|
'<td align="center">' +
|
||||||
|
'<div style="display: table-cell; vertical-align: middle;">' +
|
||||||
|
'<div style="">' + msg + '</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'</td></tr></table>';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mesasge for getting a webgl browser
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var GET_A_WEBGL_BROWSER = '' +
|
||||||
|
'This page requires a browser that supports WebGL.<br/>' +
|
||||||
|
'<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mesasge for need better hardware
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
var OTHER_PROBLEM = '' +
|
||||||
|
"It doesn't appear your computer can support WebGL.<br/>" +
|
||||||
|
'<a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webgl context. If creation fails it will
|
||||||
|
* change the contents of the container of the <canvas>
|
||||||
|
* tag to an error message with the correct links for WebGL.
|
||||||
|
* @param {Element} canvas. The canvas element to create a
|
||||||
|
* context from.
|
||||||
|
* @param {WebGLContextCreationAttirbutes} opt_attribs Any
|
||||||
|
* creation attributes you want to pass in.
|
||||||
|
* @return {WebGLRenderingContext} The created context.
|
||||||
|
*/
|
||||||
|
var setupWebGL = function(canvas, opt_attribs) {
|
||||||
|
function showLink(str) {
|
||||||
|
var container = canvas.parentNode;
|
||||||
|
if (container) {
|
||||||
|
container.innerHTML = makeFailHTML(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!window.WebGLRenderingContext) {
|
||||||
|
showLink(GET_A_WEBGL_BROWSER);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = create3DContext(canvas, opt_attribs);
|
||||||
|
if (!context) {
|
||||||
|
showLink(OTHER_PROBLEM);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a webgl context.
|
||||||
|
* @param {!Canvas} canvas The canvas tag to get context
|
||||||
|
* from. If one is not passed in one will be created.
|
||||||
|
* @return {!WebGLContext} The created context.
|
||||||
|
*/
|
||||||
|
var create3DContext = function(canvas, opt_attribs) {
|
||||||
|
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
|
||||||
|
var context = null;
|
||||||
|
for (var ii = 0; ii < names.length; ++ii) {
|
||||||
|
try {
|
||||||
|
context = canvas.getContext(names[ii], opt_attribs);
|
||||||
|
} catch(e) {}
|
||||||
|
if (context) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
create3DContext: create3DContext,
|
||||||
|
setupWebGL: setupWebGL
|
||||||
|
};
|
||||||
|
}();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides requestAnimationFrame in a cross browser way.
|
||||||
|
*/
|
||||||
|
window.requestAnimFrame = (function() {
|
||||||
|
return window.requestAnimationFrame ||
|
||||||
|
window.webkitRequestAnimationFrame ||
|
||||||
|
window.mozRequestAnimationFrame ||
|
||||||
|
window.oRequestAnimationFrame ||
|
||||||
|
window.msRequestAnimationFrame ||
|
||||||
|
function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
|
||||||
|
return window.setTimeout(callback, 1000/60);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides cancelAnimationFrame in a cross browser way.
|
||||||
|
*/
|
||||||
|
window.cancelAnimFrame = (function() {
|
||||||
|
return window.cancelAnimationFrame ||
|
||||||
|
window.webkitCancelAnimationFrame ||
|
||||||
|
window.mozCancelAnimationFrame ||
|
||||||
|
window.oCancelAnimationFrame ||
|
||||||
|
window.msCancelAnimationFrame ||
|
||||||
|
window.clearTimeout;
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue