/* Javascript port of CubicVR 3D engine for WebGL by Charles J. Cliffe http://www.cubicvr.org/ May be used under the terms of LGPL v3.0 or greater. */ /*globals alert: false */ /** Global Constants **/ var M_PI = 3.1415926535897932384626433832795028841968; var M_TWO_PI = 2.0 * M_PI; var M_HALF_PI = M_PI / 2.0; var SCRIPT_LOCATION = ""; try { Array.forEach(document.querySelectorAll("script"), function (a) { var pos = a.src.lastIndexOf('/CubicVR.js'); if (pos > -1) { SCRIPT_LOCATION = a.src.substr(0, pos) + "/"; } //if }); } catch(e) { // likely that 'document' is not defined (doesn't really matter) } //try (function(undef) { var CubicVR = this.CubicVR = {}; var GLCore = {}; var Materials = []; var Material_ref = []; var Textures = []; var Textures_obj = []; var Texture_ref = []; var Images = []; var ShaderPool = []; var MeshPool = []; var CoreShader_vs = null; var CoreShader_fs = null; var log; try { log = (console !== undefined && console.log) ? function(msg) { console.log("CubicVR Log: " + msg); } : function() {}; } catch(e) { log = function() {}; } //try var enums = { // Math math: {}, frustum: { plane: { LEFT: 0, RIGHT: 1, TOP: 2, BOTTOM: 3, NEAR: 4, FAR: 5 } }, octree: { TOP_NW: 0, TOP_NE: 1, TOP_SE: 2, TOP_SW: 3, BOTTOM_NW: 4, BOTTOM_NE: 5, BOTTOM_SE: 6, BOTTOM_SW: 7 }, // Light Types light: { type: { NULL: 0, POINT: 1, DIRECTIONAL: 2, SPOT: 3, AREA: 4, MAX: 5 }, method: { GLOBAL: 0, STATIC: 1, DYNAMIC: 2 } }, // Texture Types texture: { map: { COLOR: 0, ENVSPHERE: 1, NORMAL: 2, BUMP: 3, REFLECT: 4, SPECULAR: 5, AMBIENT: 6, ALPHA: 7, MAX: 8 }, filter: { LINEAR: 0, LINEAR_MIP: 1, NEAREST: 2, NEAREST_MIP: 3 } }, uv: { /* UV Axis enums */ axis: { X: 0, Y: 1, Z: 2 }, /* UV Projection enums */ projection: { UV: 0, PLANAR: 1, CYLINDRICAL: 2, SPHERICAL: 3, CUBIC: 4, SKY: 5 } }, // Shader Map Inputs (binary hash index) shader: { map: { COLOR: 1, SPECULAR: 2, NORMAL: 4, BUMP: 8, REFLECT: 16, ENVSPHERE: 32, AMBIENT: 64, ALPHA: 128 }, /* Uniform types */ uniform: { MATRIX: 0, VECTOR: 1, FLOAT: 2, ARRAY_VERTEX: 3, ARRAY_UV: 4, ARRAY_FLOAT: 5, INT: 6 } }, motion: { POS: 0, ROT: 1, SCL: 2, FOV: 3, LENS: 4, NEARCLIP: 5, FARCLIP: 6, INTENSITY: 7, X: 0, Y: 1, Z: 2, V: 3 }, envelope: { shape: { TCB: 0, HERM: 1, BEZI: 2, LINE: 3, STEP: 4, BEZ2: 5 }, behavior: { RESET: 0, CONSTANT: 1, REPEAT: 2, OSCILLATE: 3, OFFSET: 4, LINEAR: 5 } }, /* Post Processing */ post: { output: { REPLACE: 0, BLEND: 1, ADD: 2, ALPHACUT: 3 } } }; var cubicvr_identity = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]; /* Base functions */ var vec2 = { equal: function(a, b) { var epsilon = 0.00000001; if ((a === undef) && (b === undef)) { return true; } if ((a === undef) || (b === undef)) { return false; } return (Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon); } }; var vec3 = { length: function(pt) { return Math.sqrt(pt[0] * pt[0] + pt[1] * pt[1] + pt[2] * pt[2]); }, normalize: function(pt) { var d = Math.sqrt((pt[0] * pt[0]) + (pt[1] * pt[1]) + (pt[2] * pt[2])); if (d === 0) { return [0, 0, 0]; } return [pt[0] / d, pt[1] / d, pt[2] / d]; }, dot: function(v1, v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; }, angle: function(v1, v2) { var a = Math.acos((v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]) / (Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]) * Math.sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]))); return a; }, cross: function(vectA, vectB) { return [ vectA[1] * vectB[2] - vectB[1] * vectA[2], vectA[2] * vectB[0] - vectB[2] * vectA[0], vectA[0] * vectB[1] - vectB[0] * vectA[1]]; }, multiply: function(vectA, constB) { return [vectA[0] * constB, vectA[1] * constB, vectA[2] * constB]; }, add: function(vectA, vectB) { return [vectA[0] + vectB[0], vectA[1] + vectB[1], vectA[2] + vectB[2]]; }, subtract: function(vectA, vectB) { return [vectA[0] - vectB[0], vectA[1] - vectB[1], vectA[2] - vectB[2]]; }, equal: function(a, b) { var epsilon = 0.0000001; if ((a === undef) && (b === undef)) { return true; } if ((a === undef) || (b === undef)) { return false; } return (Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon && Math.abs(a[2] - b[2]) < epsilon); }, moveViewRelative: function(position, target, xdelta, zdelta, alt_source) { var ang = Math.atan2(zdelta, xdelta); var cam_ang = Math.atan2(target[2] - position[2], target[0] - position[0]); var mag = Math.sqrt(xdelta * xdelta + zdelta * zdelta); var move_ang = cam_ang + ang + M_HALF_PI; if (typeof(alt_source) === 'object') { return [alt_source[0] + mag * Math.cos(move_ang), alt_source[1], alt_source[2] + mag * Math.sin(move_ang)]; } return [position[0] + mag * Math.cos(move_ang), position[1], position[2] + mag * Math.sin(move_ang)]; }, trackTarget: function(position, target, trackingSpeed, safeDistance) { var camv = vec3.subtract(target, position); var dist = camv; var fdist = vec3.length(dist); var motionv = camv; motionv = vec3.normalize(motionv); motionv = vec3.multiply(motionv, trackingSpeed * (1.0 / (1.0 / (fdist - safeDistance)))); var ret_pos; if (fdist > safeDistance) { ret_pos = vec3.add(position, motionv); } else if (fdist < safeDistance) { motionv = camv; motionv = vec3.normalize(motionv); motionv = vec3.multiply(motionv, trackingSpeed * (1.0 / (1.0 / (Math.abs(fdist - safeDistance))))); ret_pos = vec3.subtract(position, motionv); } else { ret_pos = [position[0], position[1] + motionv[2], position[2]]; } return ret_pos; }, get_closest_to: function(ptA, ptB, ptTest) { var S, T, U; S = vec3.subtract(ptB, ptA); T = vec3.subtract(ptTest, ptA); U = vec3.add(vec3.multiply(S, vec3.dot(S, T) / vec3.dot(S, S)), ptA); return U; } }; var triangle = { normal: function(pt1, pt2, pt3) { var v10 = pt1[0] - pt2[0]; var v11 = pt1[1] - pt2[1]; var v12 = pt1[2] - pt2[2]; var v20 = pt2[0] - pt3[0]; var v21 = pt2[1] - pt3[1]; var v22 = pt2[2] - pt3[2]; return [v11 * v22 - v12 * v21, v12 * v20 - v10 * v22, v10 * v21 - v11 * v20]; } }; var mat3 = { transpose_inline: function(mat) { var a01 = mat[1], a02 = mat[2], a12 = mat[5]; mat[1] = mat[3]; mat[2] = mat[6]; mat[3] = a01; mat[5] = mat[7]; mat[6] = a02; mat[7] = a12; } } var mat4 = { lookat: function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz) { var forward = [], side = [], up = []; var m = []; forward[0] = centerx - eyex; forward[1] = centery - eyey; forward[2] = centerz - eyez; up[0] = upx; up[1] = upy; up[2] = upz; forward = vec3.normalize(forward); /* Side = forward x up */ var side = vec3.cross(forward, up); side = vec3.normalize(side); /* Recompute up as: up = side x forward */ up = vec3.cross(side, forward); var m = [ side[0], up[0], -forward[0], 0, side[1], up[1], -forward[1], 0, side[2], up[2], -forward[2], 0, 0, 0, 0, 1]; var t = new Transform(m); t.translate([-eyex,-eyey,-eyez]); return t.getResult(); }, multiply: function (m1, m2) { var mOut = []; mOut[0] = m2[0] * m1[0] + m2[4] * m1[1] + m2[8] * m1[2] + m2[12] * m1[3]; mOut[1] = m2[1] * m1[0] + m2[5] * m1[1] + m2[9] * m1[2] + m2[13] * m1[3]; mOut[2] = m2[2] * m1[0] + m2[6] * m1[1] + m2[10] * m1[2] + m2[14] * m1[3]; mOut[3] = m2[3] * m1[0] + m2[7] * m1[1] + m2[11] * m1[2] + m2[15] * m1[3]; mOut[4] = m2[0] * m1[4] + m2[4] * m1[5] + m2[8] * m1[6] + m2[12] * m1[7]; mOut[5] = m2[1] * m1[4] + m2[5] * m1[5] + m2[9] * m1[6] + m2[13] * m1[7]; mOut[6] = m2[2] * m1[4] + m2[6] * m1[5] + m2[10] * m1[6] + m2[14] * m1[7]; mOut[7] = m2[3] * m1[4] + m2[7] * m1[5] + m2[11] * m1[6] + m2[15] * m1[7]; mOut[8] = m2[0] * m1[8] + m2[4] * m1[9] + m2[8] * m1[10] + m2[12] * m1[11]; mOut[9] = m2[1] * m1[8] + m2[5] * m1[9] + m2[9] * m1[10] + m2[13] * m1[11]; mOut[10] = m2[2] * m1[8] + m2[6] * m1[9] + m2[10] * m1[10] + m2[14] * m1[11]; mOut[11] = m2[3] * m1[8] + m2[7] * m1[9] + m2[11] * m1[10] + m2[15] * m1[11]; mOut[12] = m2[0] * m1[12] + m2[4] * m1[13] + m2[8] * m1[14] + m2[12] * m1[15]; mOut[13] = m2[1] * m1[12] + m2[5] * m1[13] + m2[9] * m1[14] + m2[13] * m1[15]; mOut[14] = m2[2] * m1[12] + m2[6] * m1[13] + m2[10] * m1[14] + m2[14] * m1[15]; mOut[15] = m2[3] * m1[12] + m2[7] * m1[13] + m2[11] * m1[14] + m2[15] * m1[15]; return mOut; }, vec4_multiply: function (m1, m2) { var mOut = []; mOut[0] = m2[0] * m1[0] + m2[4] * m1[1] + m2[8] * m1[2] + m2[12] * m1[3]; mOut[1] = m2[1] * m1[0] + m2[5] * m1[1] + m2[9] * m1[2] + m2[13] * m1[3]; mOut[2] = m2[2] * m1[0] + m2[6] * m1[1] + m2[10] * m1[2] + m2[14] * m1[3]; mOut[3] = m2[3] * m1[0] + m2[7] * m1[1] + m2[11] * m1[2] + m2[15] * m1[3]; return mOut; }, vec3_multiply: function (m1, m2) { var mOut = []; mOut[0] = m2[0] * m1[0] + m2[4] * m1[1] + m2[8] * m1[2] + m2[12]; mOut[1] = m2[1] * m1[0] + m2[5] * m1[1] + m2[9] * m1[2] + m2[13]; mOut[2] = m2[2] * m1[0] + m2[6] * m1[1] + m2[10] * m1[2] + m2[14]; return mOut; }, perspective: function (fovy, aspect, near, far) { var yFac = Math.tan(fovy * M_PI / 360.0); var xFac = yFac * aspect; return [ 1.0 / xFac, 0, 0, 0, 0, 1.0 / yFac, 0, 0, 0, 0, -(far + near) / (far - near), -1, 0, 0, -(2.0 * far * near) / (far - near), 0]; }, determinant: function (m) { var a0 = m[0] * m[5] - m[1] * m[4]; var a1 = m[0] * m[6] - m[2] * m[4]; var a2 = m[0] * m[7] - m[3] * m[4]; var a3 = m[1] * m[6] - m[2] * m[5]; var a4 = m[1] * m[7] - m[3] * m[5]; var a5 = m[2] * m[7] - m[3] * m[6]; var b0 = m[8] * m[13] - m[9] * m[12]; var b1 = m[8] * m[14] - m[10] * m[12]; var b2 = m[8] * m[15] - m[11] * m[12]; var b3 = m[9] * m[14] - m[10] * m[13]; var b4 = m[9] * m[15] - m[11] * m[13]; var b5 = m[10] * m[15] - m[11] * m[14]; var det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; return det; }, coFactor: function (m, n, out) { // .. todo.. }, transpose: function (m) { return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]]; }, inverse_mat3: function(mat) { var dest = []; var a00 = mat[0], a01 = mat[1], a02 = mat[2], a10 = mat[4], a11 = mat[5], a12 = mat[6], a20 = mat[8], a21 = mat[9], a22 = mat[10]; var b01 = a22*a11-a12*a21, b11 = -a22*a10+a12*a20, b21 = a21*a10-a11*a20; var d = a00*b01 + a01*b11 + a02*b21; if (!d) { return null; } var id = 1/d; dest[0] = b01*id; dest[1] = (-a22*a01 + a02*a21)*id; dest[2] = (a12*a01 - a02*a11)*id; dest[3] = b11*id; dest[4] = (a22*a00 - a02*a20)*id; dest[5] = (-a12*a00 + a02*a10)*id; dest[6] = b21*id; dest[7] = (-a21*a00 + a01*a20)*id; dest[8] = (a11*a00 - a01*a10)*id; return dest; }, // not sure which is faster yet.. inverse$1: function (m) { var tmp = []; var src = []; var dst = []; // Transpose matrix for (var i = 0; i < 4; i++) { src[i + 0] = m[i*4 + 0]; src[i + 4] = m[i*4 + 1]; src[i + 8] = m[i*4 + 2]; src[i + 12] = m[i*4 + 3]; } // Calculate pairs for first 8 elements (cofactors) tmp[0] = src[10] * src[15]; tmp[1] = src[11] * src[14]; tmp[2] = src[9] * src[15]; tmp[3] = src[11] * src[13]; tmp[4] = src[9] * src[14]; tmp[5] = src[10] * src[13]; tmp[6] = src[8] * src[15]; tmp[7] = src[11] * src[12]; tmp[8] = src[8] * src[14]; tmp[9] = src[10] * src[12]; tmp[10] = src[8] * src[13]; tmp[11] = src[9] * src[12]; // Calculate first 8 elements (cofactors) dst[0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7]; dst[0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7]; dst[1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7]; dst[1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7]; dst[2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7]; dst[2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7]; dst[3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6]; dst[3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6]; dst[4] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3]; dst[4] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3]; dst[5] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3]; dst[5] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3]; dst[6] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3]; dst[6] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3]; dst[7] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2]; dst[7] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2]; // Calculate pairs for second 8 elements (cofactors) tmp[0] = src[2]*src[7]; tmp[1] = src[3]*src[6]; tmp[2] = src[1]*src[7]; tmp[3] = src[3]*src[5]; tmp[4] = src[1]*src[6]; tmp[5] = src[2]*src[5]; tmp[6] = src[0]*src[7]; tmp[7] = src[3]*src[4]; tmp[8] = src[0]*src[6]; tmp[9] = src[2]*src[4]; tmp[10] = src[0]*src[5]; tmp[11] = src[1]*src[4]; // Calculate second 8 elements (cofactors) dst[8] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]; dst[8] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]; dst[9] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]; dst[9] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]; dst[10] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10]* src[15]; dst[10] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11]* src[15]; dst[11] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11]* src[14]; dst[11] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10]* src[14]; dst[12] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]; dst[12] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]; dst[13] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]; dst[13] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]; dst[14] = tmp[6] * src[9] + tmp[11]* src[11] + tmp[3] * src[8]; dst[14] -= tmp[10]* src[11 ] + tmp[2] * src[8] + tmp[7] * src[9]; dst[15] = tmp[10]* src[10] + tmp[4] * src[8] + tmp[9] * src[9]; dst[15] -= tmp[8] * src[9] + tmp[11]* src[10] + tmp[5] * src[8]; // Calculate determinant var det = src[0]*dst[0] + src[1]*dst[1] + src[2]*dst[2] + src[3]*dst[3]; var ret = []; // Calculate matrix inverse det = 1.0 / det; for (var i = 0; i < 16; i++) { ret[i] = dst[i] * det; } return ret; }, inverse$2: function (m) { var inv = []; inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15] + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10]; inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15] - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10]; inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15] + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9]; inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14] - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9]; inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15] - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10]; inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15] + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10]; inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15] - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9]; inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14] + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9]; inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15] + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6]; inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15] - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6]; inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15] + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5]; inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14] - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5]; inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11] - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6]; inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11] + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6]; inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11] - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5]; inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10] + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5]; det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12]; if (det == 0) return null; inverse_det = 1.0 / det; inv[0] *= inverse_det; inv[1] *= inverse_det; inv[2] *= inverse_det; inv[3] *= inverse_det; inv[4] *= inverse_det; inv[5] *= inverse_det; inv[6] *= inverse_det; inv[7] *= inverse_det; inv[8] *= inverse_det; inv[9] *= inverse_det; inv[10] *= inverse_det; inv[11] *= inverse_det; inv[12] *= inverse_det; inv[13] *= inverse_det; inv[14] *= inverse_det; inv[15] *= inverse_det; return inv; }, inverse: function (m) { var a0 = m[0] * m[5] - m[1] * m[4]; var a1 = m[0] * m[6] - m[2] * m[4]; var a2 = m[0] * m[7] - m[3] * m[4]; var a3 = m[1] * m[6] - m[2] * m[5]; var a4 = m[1] * m[7] - m[3] * m[5]; var a5 = m[2] * m[7] - m[3] * m[6]; var b0 = m[8] * m[13] - m[9] * m[12]; var b1 = m[8] * m[14] - m[10] * m[12]; var b2 = m[8] * m[15] - m[11] * m[12]; var b3 = m[9] * m[14] - m[10] * m[13]; var b4 = m[9] * m[15] - m[11] * m[13]; var b5 = m[10] * m[15] - m[11] * m[14]; var determinant = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; if (determinant != 0) { var m_inv = []; m_inv[0] = 0 + m[5] * b5 - m[6] * b4 + m[7] * b3; m_inv[4] = 0 - m[4] * b5 + m[6] * b2 - m[7] * b1; m_inv[8] = 0 + m[4] * b4 - m[5] * b2 + m[7] * b0; m_inv[12] = 0 - m[4] * b3 + m[5] * b1 - m[6] * b0; m_inv[1] = 0 - m[1] * b5 + m[2] * b4 - m[3] * b3; m_inv[5] = 0 + m[0] * b5 - m[2] * b2 + m[3] * b1; m_inv[9] = 0 - m[0] * b4 + m[1] * b2 - m[3] * b0; m_inv[13] = 0 + m[0] * b3 - m[1] * b1 + m[2] * b0; m_inv[2] = 0 + m[13] * a5 - m[14] * a4 + m[15] * a3; m_inv[6] = 0 - m[12] * a5 + m[14] * a2 - m[15] * a1; m_inv[10] = 0 + m[12] * a4 - m[13] * a2 + m[15] * a0; m_inv[14] = 0 - m[12] * a3 + m[13] * a1 - m[14] * a0; m_inv[3] = 0 - m[9] * a5 + m[10] * a4 - m[11] * a3; m_inv[7] = 0 + m[8] * a5 - m[10] * a2 + m[11] * a1; m_inv[11] = 0 - m[8] * a4 + m[9] * a2 - m[11] * a0; m_inv[15] = 0 + m[8] * a3 - m[9] * a1 + m[10] * a0; var inverse_det = 1.0 / determinant; m_inv[0] *= inverse_det; m_inv[1] *= inverse_det; m_inv[2] *= inverse_det; m_inv[3] *= inverse_det; m_inv[4] *= inverse_det; m_inv[5] *= inverse_det; m_inv[6] *= inverse_det; m_inv[7] *= inverse_det; m_inv[8] *= inverse_det; m_inv[9] *= inverse_det; m_inv[10] *= inverse_det; m_inv[11] *= inverse_det; m_inv[12] *= inverse_det; m_inv[13] *= inverse_det; m_inv[14] *= inverse_det; m_inv[15] *= inverse_det; return m_inv; } return null; } }; var util = { getScriptContents: function(id) { var shaderScript = document.getElementById(id); var str = ""; var srcUrl = ""; if (!shaderScript) { srcUrl = id; } else { if (shaderScript.src !== "" || shaderScript.attributes['srcUrl'] !== undef) { srcUrl = (shaderScript.src !== '') ? shaderScript.src : (shaderScript.attributes['srcUrl'].value); } } if (srcUrl.length !== 0) { var xmlHttp = new XMLHttpRequest(); xmlHttp.open('GET', srcUrl, false); xmlHttp.send(null); if (xmlHttp.status === 200 || xmlHttp.status === 0) { str = xmlHttp.responseText; } } else { var k = shaderScript.firstChild; while (k) { if (k.nodeType === 3) { str += k.textContent; } k = k.nextSibling; } } return str; }, getURL: function(srcUrl) { try { var xmlHttp = new XMLHttpRequest(); xmlHttp.open('GET', srcUrl, false); xmlHttp.send(null); if (xmlHttp.status === 200 || xmlHttp.status === 0) { if (xmlHttp.responseText.length) { return xmlHttp.responseText; } else if (xmlHttp.responseXML) { return xmlHttp.responseXML; } } } catch(e) { alert(srcUrl + " failed to load."); } return null; }, getXML: function(srcUrl) { try { var xmlHttp = new XMLHttpRequest(); xmlHttp.open('GET', srcUrl, false); xmlHttp.overrideMimeType("application/xml"); xmlHttp.send(null); if (xmlHttp.status === 200 || xmlHttp.status === 0) { return xmlHttp.responseXML; } } catch(e) { try { alert(srcUrl + " failed to load."); } catch (ex) { throw(e); } } return null; }, repackArray: function(data, stride, count) { if (data.length !== parseInt(stride, 10) * parseInt(count, 10)) { log("array repack error, data size !== stride*count: data.length=" + data.length + " stride=" + stride + " count=" + count); } var returnData = []; var c = 0; for (var i = 0, iMax = data.length; i < iMax; i++) { var ims = i % stride; if (ims === 0) { returnData[c] = []; } returnData[c][ims] = data[i]; if (ims === stride - 1) { c++; } } return returnData; }, collectTextNode: function(tn) { if (!tn) { return ""; } var s = ""; var textNodeChildren = tn.childNodes; for (var i = 0, tnl = textNodeChildren.length; i < tnl; i++) { s += textNodeChildren[i].nodeValue; } return s; }, floatDelimArray: function(float_str, delim) { // if (!float_str) return []; var fa = float_str.split(delim ? delim : ","); for (var i = 0, imax = fa.length; i < imax; i++) { fa[i] = parseFloat(fa[i]); } if (fa[fa.length - 1] !== fa[fa.length - 1]) { fa.pop(); } return fa; }, intDelimArray: function(float_str, delim) { // if (!float_str) return []; var fa = float_str.split(delim ? delim : ","); for (var i = 0, imax = fa.length; i < imax; i++) { fa[i] = parseInt(fa[i], 10); } if (fa[fa.length - 1] !== fa[fa.length - 1]) { fa.pop(); } return fa; }, textDelimArray: function(text_str, delim) { // if (!text_str) return ""; var fa = text_str.split(delim ? delim : ","); for (var i = 0, imax = fa.length; i < imax; i++) { fa[i] = fa[i]; } return fa; } }; var MAX_LIGHTS=6; /* Core Init, single context only at the moment */ GLCore.init = function(gl_in, vs_in, fs_in) { var gl; if (gl_in.getContext!==undef&&gl_in.width!==undef&&gl_in.height!==undef) { try { gl = gl_in.getContext("experimental-webgl"); gl.viewport(0, 0, gl_in.width, gl_in.height); // set these default, can always be easily over-ridden gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clearDepth(1.0); gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); } catch (e) {} if (!gl) { // alert("Could not initialise WebGL, sorry :-("); return null; } } else { gl = gl_in; } GLCore.gl = gl; GLCore.CoreShader_vs = util.getScriptContents(vs_in); GLCore.CoreShader_fs = util.getScriptContents(fs_in); GLCore.depth_alpha = false; GLCore.default_filter = enums.texture.filter.LINEAR_MIP; GLCore.mainloop = null; gl.enable(gl.CULL_FACE); gl.cullFace(gl.BACK); gl.frontFace(gl.CCW); for (var i = enums.light.type.NULL; i < enums.light.type.MAX; i++) { ShaderPool[i] = []; } var dummyTex = new CubicVR.Texture(); var lightTest = new CubicVR.Material(); for (var i = 0; i < enums.texture.map.MAX; i++) { if (i===enums.texture.map.BUMP) continue; // fix for crashy fglrx driver, todo: check it against newer revisions. lightTest.setTexture(dummyTex,i); } lightTest.opacity = 0.5; var lc = 1; try { while (1) { lightTest.use(enums.light.type.POINT,lc); if (lc === 8) { MAX_LIGHTS=lc; break; } lc++; } } catch (e) { MAX_LIGHTS=lc; // console.log(e); } log("Calibrated maximum lights per pass to: "+lc); for (var i = enums.light.type.NULL; i < enums.light.type.MAX; i++) { ShaderPool[i] = []; } return gl; }; GLCore.setDepthAlpha = function(da, near, far) { GLCore.depth_alpha = da; GLCore.depth_alpha_near = near; GLCore.depth_alpha_far = far; }; GLCore.setDefaultFilter = function(filterType) { GLCore.default_filter = filterType; }; var cubicvr_compileShader = function(gl, str, type) { var shader; if (type === "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if (type === "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER); } else { return null; } gl.shaderSource(shader, str); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { log(gl.getShaderInfoLog(shader)); return null; } return shader; }; var cubicvr_getShader = function(gl, id) { var shaderScript = document.getElementById(id); if (!shaderScript) { return null; } var str = ""; var k = shaderScript.firstChild; while (k) { if (k.nodeType === 3) { str += k.textContent; } k = k.nextSibling; } var shader; if (shaderScript.type === "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if (shaderScript.type === "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER); } else { return null; } gl.shaderSource(shader, str); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { log(gl.getShaderInfoLog(shader)); // return null; } return shader; }; /***************************************************************************** * Workers *****************************************************************************/ function CubicVR_Worker(settings) { this.worker = new Worker(SCRIPT_LOCATION + "CubicVR.js"); this.message = settings.message; this.error = settings.error; this.type = settings.type; var that = this; this.worker.onmessage = function(e) { if (that.message) { that.message(e.data); } //if }; this.worker.onerror = function(e) { if (that.error) { that.error(e); } else { log("Error: " + e.message + ": " + e.lineno); } //if }; //onerror this.fn = function(fn, options) { that.worker.postMessage({ message: "function", data: fn, options: options, }); }; this.start = function(options) { that.worker.postMessage({ message: "start", data: that.type, options: options }); }; this.init = function(data) { that.send({message:'init', data:data}); }; this.stop = function() { that.worker.postMessage({ message: "stop", data: null }); }; this.send = function(message) { that.worker.postMessage({ message: "data", data: message }); }; }; //CubicVR_Worker::Constructor function CubicVR_TestWorker() { var that = this; this.onmessage = function(message) { if (message.test) { setTimeout(function(){postMessage(message.test);}, 1000); } else { setTimeout(function(){throw new Error(message);}, 1000); } //if }; //onmessage }; //CubicVR_TestWorker function CubicVR_ColladaLoadWorker() { var that = this; this.onmessage = function(message) { }; //onmessage }; //CubicVR_ColladaLoadWorker function CubicVR_WorkerConnection() { this.listener = null; } //CubicVR_WorkerConnection var WorkerConnection = new CubicVR_WorkerConnection(); if (1) { self.addEventListener('message', function(e) { var message = e.data.message; var type = e.data.data; if (message === "start") { if (type === "test") { WorkerConnection.listener = new CubicVR_TestWorker(); } else if (type === "load_collada") { WorkerConnection.listener = new CubicVR_ColladaLoadWorker(); } else if (type === "octree") { WorkerConnection.listener = new CubicVR_OctreeWorker(); } //if } else if (message === "function") { var data = e.data.data; var options = e.data.options; var parts = data.split('('); if (parts.length > 1 && parts[1].indexOf(')') > -1) { var prefix = parts[0]; var suffix = parts[1].substr(0,parts[1].length-1); var args = options || suffix.split(','); var chain = prefix.split('.'); var fn = CubicVR; for (var i=0; i 1000) dist = 1000; // if (camDist > 20.0) camDist = 20.0; ctx.camera.position = vec3.add(ctx.camera.target,vec3.multiply(vec3.normalize(vec3.subtract(ctx.camera.position,ctx.camera.target)),dist)); } }(); this.bind(); } MouseViewController.prototype.bind = function() { this.canvas.addEventListener('mousemove', this.onMouseMove, false); this.canvas.addEventListener('mousedown', this.onMouseDown, false); this.canvas.addEventListener('mouseup', this.onMouseUp, false); this.canvas.addEventListener('mousewheel', this.onMouseWheel, false); this.canvas.addEventListener('DOMMouseScroll', this.onMouseWheel, false); }; MouseViewController.prototype.unbind = function() { this.canvas.removeEventListener('mousemove', this.onMouseMove, false); this.canvas.removeEventListener('mousedown', this.onMouseDown, false); this.canvas.removeEventListener('mouseup', this.onMouseUp, false); this.canvas.removeEventListener('mousewheel', this.onMouseWheel, false); this.canvas.removeEventListener('DOMMouseScroll', this.onMouseWheel, false); }; MouseViewController.prototype.setCamera = function(cam_in) { this.camera = cam_in; } MouseViewController.prototype.getMousePosition = function() { return this.mpos; } /* Transform Controller */ function Transform(init_mat) { return this.clearStack(init_mat); } Transform.prototype.setIdentity = function() { this.m_stack[this.c_stack] = [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]; if (this.valid === this.c_stack && this.c_stack) { this.valid--; } return this; }; Transform.prototype.getIdentity = function() { return [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]; }; Transform.prototype.invalidate = function() { this.valid = 0; this.result = null; return this; }; Transform.prototype.getResult = function() { if (!this.c_stack) { return this.m_stack[0]; } var m = cubicvr_identity; if (this.valid > this.c_stack-1) this.valid = this.c_stack-1; for (var i = this.valid; i < this.c_stack+1; i++) { m = mat4.multiply(this.m_stack[i],m); this.m_cache[i] = m; } this.valid = this.c_stack-1; this.result = this.m_cache[this.c_stack]; return this.result; }; Transform.prototype.pushMatrix = function(m) { this.c_stack++; this.m_stack[this.c_stack] = (m ? m : cubicvr_identity); return this; }; Transform.prototype.popMatrix = function() { if (this.c_stack === 0) { return; } this.c_stack--; return this; }; Transform.prototype.clearStack = function(init_mat) { this.m_stack = []; this.m_cache = []; this.c_stack = 0; this.valid = 0; this.result = null; if (init_mat !== undef) { this.m_stack[0] = init_mat; } else { this.setIdentity(); } return this; }; Transform.prototype.translate = function(x, y, z) { if (typeof(x) === 'object') { return this.translate(x[0], x[1], x[2]); } var m = this.getIdentity(); m[12] = x; m[13] = y; m[14] = z; this.m_stack[this.c_stack] = mat4.multiply(m,this.m_stack[this.c_stack]); if (this.valid === this.c_stack && this.c_stack) { this.valid--; } return this; }; Transform.prototype.scale = function(x, y, z) { if (typeof(x) === 'object') { return this.scale(x[0], x[1], x[2]); } var m = this.getIdentity(); m[0] = x; m[5] = y; m[10] = z; this.m_stack[this.c_stack] = mat4.multiply(m,this.m_stack[this.c_stack]); if (this.valid === this.c_stack && this.c_stack) { this.valid--; } return this; }; Transform.prototype.rotate = function(ang, x, y, z) { if (typeof(ang) === 'object') { this.rotate(ang[0], 1, 0, 0); this.rotate(ang[1], 0, 1, 0); this.rotate(ang[2], 0, 0, 1); return this; } var sAng, cAng; if (x || y || z) { sAng = Math.sin(-ang * (M_PI / 180.0)); cAng = Math.cos(-ang * (M_PI / 180.0)); } if (z) { var Z_ROT = this.getIdentity(); Z_ROT[0] = cAng * z; Z_ROT[4] = sAng * z; Z_ROT[1] = -sAng * z; Z_ROT[5] = cAng * z; this.m_stack[this.c_stack] = mat4.multiply(this.m_stack[this.c_stack],Z_ROT); } if (y) { var Y_ROT = this.getIdentity(); Y_ROT[0] = cAng * y; Y_ROT[8] = -sAng * y; Y_ROT[2] = sAng * y; Y_ROT[10] = cAng * y; this.m_stack[this.c_stack] = mat4.multiply(this.m_stack[this.c_stack],Y_ROT); } if (x) { var X_ROT = this.getIdentity(); X_ROT[5] = cAng * x; X_ROT[9] = sAng * x; X_ROT[6] = -sAng * x; X_ROT[10] = cAng * x; this.m_stack[this.c_stack] = mat4.multiply(this.m_stack[this.c_stack],X_ROT); } if (this.valid === this.c_stack && this.c_stack) { this.valid--; } return this; }; /* Quaternions */ function Quaternion() { if (arguments.length === 1) { this.x = arguments[0][0]; this.y = arguments[0][1]; this.z = arguments[0][2]; this.w = arguments[0][3]; } if (arguments.length === 4) { this.x = arguments[0]; this.y = arguments[1]; this.z = arguments[2]; this.w = arguments[3]; } } Quaternion.prototype.length = function() { return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); }; Quaternion.prototype.normalize = function() { var n = Math.sqrt(this.length()); this.x /= n; this.y /= n; this.z /= n; this.w /= n; }; Quaternion.prototype.fromEuler = function(bank, heading, pitch) // x,y,z { var c1 = Math.cos((M_PI / 180.0) * heading / 2.0); var s1 = Math.sin((M_PI / 180.0) * heading / 2.0); var c2 = Math.cos((M_PI / 180.0) * pitch / 2.0); var s2 = Math.sin((M_PI / 180.0) * pitch / 2.0); var c3 = Math.cos((M_PI / 180.0) * bank / 2.0); var s3 = Math.sin((M_PI / 180.0) * bank / 2.0); var c1c2 = c1 * c2; var s1s2 = s1 * s2; this.w = c1c2 * c3 - s1s2 * s3; this.x = c1c2 * s3 + s1s2 * c3; this.y = s1 * c2 * c3 + c1 * s2 * s3; this.z = c1 * s2 * c3 - s1 * c2 * s3; }; Quaternion.prototype.toEuler = function() { var sqw = this.w * this.w; var sqx = this.x * this.x; var sqy = this.y * this.y; var sqz = this.z * this.z; var x = (180 / M_PI) * ((Math.atan2(2.0 * (this.y * this.z + this.x * this.w), (-sqx - sqy + sqz + sqw)))); var y = (180 / M_PI) * ((Math.asin(-2.0 * (this.x * this.z - this.y * this.w)))); var z = (180 / M_PI) * ((Math.atan2(2.0 * (this.x * this.y + this.z * this.w), (sqx - sqy - sqz + sqw)))); return [x, y, z]; }; Quaternion.prototype.multiply = function(q1, q2) { var selfSet = false; if (q2 === undef) { q2 = q1; q1 = this; } var x = q1.x * q2.w + q1.w * q2.x + q1.y * q2.z - q1.z * q2.y; var y = q1.y * q2.w + q1.w * q2.y + q1.z * q2.x - q1.x * q2.z; var z = q1.z * q2.w + q1.w * q2.z + q1.x * q2.y - q1.y * q2.x; var w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z; if (selfSet) { this.x = x; this.y = y; this.z = z; this.w = w; } else { return new Quaternion(x, y, z, w); } }; /* Faces */ function Face() { this.points = []; this.point_normals = []; this.uvs = []; this.normal = [0, 0, 0]; this.material = 0; this.segment = 0; } Face.prototype.setUV = function(uvs, point_num) { if (this.uvs === undef) { this.uvs = []; } if (point_num !== undef) { this.uvs[point_num] = uvs; } else { if (uvs.length !== 2) { this.uvs = uvs; } else { this.uvs.push(uvs); } } }; Face.prototype.flip = function() { for (var i = 0, iMax = this.point_normals.length; i < iMax; i++) { this.point_normals[i] = [this.point_normals[i][0], this.point_normals[i][1], this.point_normals[i][2]]; } this.points.reverse(); this.point_normals.reverse(); this.uvs.reverse(); this.normal = [-this.normal[0], -this.normal[1], -this.normal[2]]; }; function Mesh(objName) { this.points = []; // point list this.faces = []; // faces with point references this.currentFace = -1; // start with no faces this.currentMaterial = 0; // null material this.currentSegment = 0; // default segment this.compiled = null; // VBO data this.bb = null; this.name = objName ? objName : null; this.hasUV = false; this.hasNorm = false; } Mesh.prototype.showAllSegments = function() { for (var i in this.segment_state) { if (this.segment_state.hasOwnProperty(i)) { this.segment_state[i] = true; } } }; Mesh.prototype.hideAllSegments = function() { for (var i in this.segment_state) { if (this.segment_state.hasOwnProperty(i)) { this.segment_state[i] = false; } } }; Mesh.prototype.setSegment = function(i, val) { if (val !== undef) { this.segment_state[i] = val; } else { this.currentSegment = i; } }; Mesh.prototype.addPoint = function(p) { if (p.length !== 3 || typeof(p[0]) === 'object') { for (var i = 0, iMax = p.length; i < iMax; i++) { this.points.push(p[i]); } } else { this.points.push(p); } return this.points.length - 1; }; Mesh.prototype.setFaceMaterial = function(mat,facenum) { var mat_id = (typeof(mat) === 'object') ? mat.material_id : mat; if (facenum !== undef) { if (this.faces[facenum] !== undef) { this.faces[facenum].material = mat_id; } } else { this.currentMaterial = mat_id; } }; Mesh.prototype.addFace = function(p_list, face_num, face_mat, face_seg) { if (typeof(p_list[0]) !== 'number') { for (var i = 0, iMax = p_list.length; i < iMax; i++) { if (!p_list.hasOwnProperty(i)) { continue; } this.addFace(p_list[i]); } return; } if (face_num === undef) { this.currentFace = this.faces.length; this.faces.push(new Face()); } else { if (this.faces[face_num] === undef) { this.faces[face_num] = new Face(); } this.currentFace = face_num; } if (typeof(p_list) === 'object') { this.faces[this.currentFace].points = p_list; } if (face_mat !== undef) { this.faces[this.currentFace].material = (typeof(face_mat) === 'object') ? face_mat.material_id : face_mat; } else { this.faces[this.currentFace].material = this.currentMaterial; } if (face_seg !== undef) { this.faces[this.currentFace].segment = face_seg; } else { this.faces[this.currentFace].segment = this.currentSegment; } return this.currentFace; }; Mesh.prototype.triangulateQuads = function() { for (var i = 0, iMax = this.faces.length; i < iMax; i++) { if (this.faces[i].points.length === 4) { var p = this.faces.length; this.addFace([this.faces[i].points[2], this.faces[i].points[3], this.faces[i].points[0]], this.faces.length, this.faces[i].material, this.faces[i].segment); this.faces[i].points.pop(); this.faces[p].normal = this.faces[i].normal; if (this.faces[i].uvs !== undef) { if (this.faces[i].uvs.length === 4) { this.faces[p].setUV(this.faces[i].uvs[2], 0); this.faces[p].setUV(this.faces[i].uvs[3], 1); this.faces[p].setUV(this.faces[i].uvs[0], 2); this.faces[i].uvs.pop(); } } if (this.faces[i].point_normals.length === 4) { this.faces[p].point_normals[0] = this.faces[i].point_normals[2]; this.faces[p].point_normals[1] = this.faces[i].point_normals[3]; this.faces[p].point_normals[2] = this.faces[i].point_normals[0]; this.faces[i].point_normals.pop(); } } } return this; }; Mesh.prototype.booleanAdd = function(objAdd, transform) { var pofs = this.points.length; var fofs = this.faces.length; var i, j, iMax, jMax; if (transform !== undef) { var m = transform.getResult(); for (i = 0, iMax = objAdd.points.length; i < iMax; i++) { this.addPoint(mat4.vec3_multiply(objAdd.points[i], m)); } } else { for (i = 0, iMax = objAdd.points.length; i < iMax; i++) { this.addPoint([objAdd.points[i][0], objAdd.points[i][1], objAdd.points[i][2]]); } } for (i = 0, iMax = objAdd.faces.length; i < iMax; i++) { var newFace = []; for (j = 0, jMax = objAdd.faces[i].points.length; j < jMax; j++) { newFace.push(objAdd.faces[i].points[j] + pofs); } var nFaceNum = this.addFace(newFace); var nFace = this.faces[nFaceNum]; nFace.segment = objAdd.faces[i].segment; nFace.material = objAdd.faces[i].material; for (j = 0, jMax = objAdd.faces[i].uvs.length; j < jMax; j++) { nFace.uvs[j] = [objAdd.faces[i].uvs[j][0], objAdd.faces[i].uvs[j][1]]; } for (j = 0, jMax = objAdd.faces[i].point_normals.length; j < jMax; j++) { nFace.point_normals[j] = [objAdd.faces[i].point_normals[j][0], objAdd.faces[i].point_normals[j][1], objAdd.faces[i].point_normals[j][2]]; } } return this; }; Mesh.prototype.calcFaceNormals = function() { for (var i = 0, iMax = this.faces.length; i < iMax; i++) { if (this.faces[i].points.length < 3) { this.faces[i].normal = [0, 0, 0]; continue; } this.faces[i].normal = vec3.normalize(triangle.normal(this.points[this.faces[i].points[0]], this.points[this.faces[i].points[1]], this.points[this.faces[i].points[2]])); } return this; }; Mesh.prototype.getMaterial = function(m_name) { if (this.compiled !== null) { for (var i in this.compiled.elements) { if (this.compiled.elements.hasOwnProperty(i)) { if (Materials[i].name === m_name) { return Materials[i]; } } } } else { var matVisit = []; for (var j = 0, jMax = this.faces.length; j < jMax; j++) { var matId = this.faces[j].material; if (matVisit.indexOf(matId)===-1) { if (Materials[matId].name === m_name) { return Materials[matId]; } matVisit.push(matId); } } } return null; }; Mesh.prototype.calcNormals = function() { this.calcFaceNormals(); var i, j, k, iMax; var point_smoothRef = new Array(this.points.length); for (i = 0, iMax = point_smoothRef.length; i < iMax; i++) { point_smoothRef[i] = []; } var numFaces = this.faces.length; // build a quick list of point/face sharing for (i = 0; i < numFaces; i++) { var numFacePoints = this.faces[i].points.length; for (j = 0; j < numFacePoints; j++) { var idx = this.faces[i].points[j]; // if (point_smoothRef[idx] === undef) point_smoothRef[idx] = []; point_smoothRef[idx].push([i, j]); } } // step through smoothing references and compute normals for (i = 0, iMax = this.points.length; i < iMax; i++) { // if(!point_smoothRef.hasOwnProperty(i)) { continue; } // if (typeof(point_smoothRef[i]) === undef) { continue; } var numPts = point_smoothRef[i].length; for (j = 0; j < numPts; j++) { var ptCount = 1; var faceNum = point_smoothRef[i][j][0]; var pointNum = point_smoothRef[i][j][1]; var max_smooth = Materials[this.faces[faceNum].material].max_smooth; var thisFace = this.faces[faceNum]; // set point to it's face's normal var tmpNorm = new Array(3); tmpNorm[0] = thisFace.normal[0]; tmpNorm[1] = thisFace.normal[1]; tmpNorm[2] = thisFace.normal[2]; // step through all other faces which share this point if (max_smooth !== 0) { for (k = 0; k < numPts; k++) { if (j === k) { continue; } var faceRefNum = point_smoothRef[i][k][0]; var thisFaceRef = this.faces[faceRefNum]; var ang = vec3.angle(thisFaceRef.normal, thisFace.normal); if ((ang !== ang) || ((ang * (180.0 / M_PI)) <= max_smooth)) { tmpNorm[0] += thisFaceRef.normal[0]; tmpNorm[1] += thisFaceRef.normal[1]; tmpNorm[2] += thisFaceRef.normal[2]; ptCount++; } } } tmpNorm[0] /= ptCount; tmpNorm[1] /= ptCount; tmpNorm[2] /= ptCount; this.faces[faceNum].point_normals[pointNum] = vec3.normalize(tmpNorm); } } return this; }; Mesh.prototype.clean = function() { var i,iMax; for (i = 0, iMax=this.points.length; i < iMax; i++) { delete(this.points[i]); this.points[i]=null; } this.points = []; for (i = 0, iMax=this.faces.length; i < iMax; i++) { delete(this.faces[i].points); delete(this.faces[i].point_normals); delete(this.faces[i].uvs); delete(this.faces[i].normal); delete(this.faces[i]); this.faces[i]=null; } this.faces = []; return this; } Mesh.prototype.compile = function() { this.compiled = {}; this.bb = []; var compileRef = []; var i, j, k, x, y, iMax, kMax, yMax; for (i = 0, iMax = this.faces.length; i < iMax; i++) { if (this.faces[i].points.length === 3) { var matId = this.faces[i].material; var segId = this.faces[i].segment; if (compileRef[matId] === undef) { compileRef[matId] = []; } if (compileRef[matId][segId] === undef) { compileRef[matId][segId] = []; } compileRef[matId][segId].push(i); } } var vtxRef = []; this.compiled.vbo_normals = []; this.compiled.vbo_points = []; this.compiled.vbo_uvs = []; var idxCount = 0; var hasUV = false; var hasNorm = false; var faceNum; for (i in compileRef) { if (compileRef.hasOwnProperty(i)) { for (j in compileRef[i]) { if (compileRef[i].hasOwnProperty(j)) { for (k = 0; k < compileRef[i][j].length; k++) { faceNum = compileRef[i][j][k]; hasUV = hasUV || (this.faces[faceNum].uvs.length !== 0); hasNorm = hasNorm || (this.faces[faceNum].point_normals.length !== 0); } } } } } if (hasUV) { for (i = 0; i < this.faces.length; i++) { if (!this.faces[i].uvs.length) { for (j = 0; j < this.faces[i].points.length; j++) { this.faces[i].uvs.push([0, 0]); } } } } if (hasNorm) { for (i = 0; i < this.faces.length; i++) { if (!this.faces[i].point_normals.length) { for (j = 0; j < this.faces[i].points.length; j++) { this.faces[i].point_normals.push([0, 0, 0]); } } } } this.hasUV = hasUV; this.hasNorm = hasNorm; var pVisitor = []; for (i in compileRef) { if (compileRef.hasOwnProperty(i)) { for (j in compileRef[i]) { if (compileRef[i].hasOwnProperty(j)) { for (k = 0, kMax = compileRef[i][j].length; k < kMax; k++) { faceNum = compileRef[i][j][k]; var found = false; for (x = 0; x < 3; x++) { var ptNum = this.faces[faceNum].points[x]; var foundPt = -1; if (vtxRef[ptNum] !== undef) { for (y = 0, yMax = vtxRef[ptNum].length; y < yMax; y++) { // face / point var oFace = vtxRef[ptNum][y][0]; // faceNum var oPoint = vtxRef[ptNum][y][1]; // pointNum var oIndex = vtxRef[ptNum][y][2]; // index foundPt = oIndex; if (hasNorm) { foundPt = (vec3.equal( this.faces[oFace].point_normals[oPoint], this.faces[faceNum].point_normals[x])) ? foundPt : -1; } if (hasUV) { foundPt = (vec2.equal( this.faces[oFace].uvs[oPoint], this.faces[faceNum].uvs[x])) ? foundPt : -1; } } } if (foundPt !== -1) { if (this.compiled.elements === undef) { this.compiled.elements = []; } if (this.compiled.elements[i] === undef) { this.compiled.elements[i] = []; } if (this.compiled.elements[i][j] === undef) { this.compiled.elements[i][j] = []; } this.compiled.elements[i][j].push(foundPt); } else { this.compiled.vbo_points.push(this.points[ptNum][0]); this.compiled.vbo_points.push(this.points[ptNum][1]); this.compiled.vbo_points.push(this.points[ptNum][2]); if (this.bb.length === 0) { this.bb[0] = [this.points[ptNum][0], this.points[ptNum][1], this.points[ptNum][2]]; this.bb[1] = [this.points[ptNum][0], this.points[ptNum][1], this.points[ptNum][2]]; } else { if (this.points[ptNum][0] < this.bb[0][0]) { this.bb[0][0] = this.points[ptNum][0]; } if (this.points[ptNum][1] < this.bb[0][1]) { this.bb[0][1] = this.points[ptNum][1]; } if (this.points[ptNum][2] < this.bb[0][2]) { this.bb[0][2] = this.points[ptNum][2]; } if (this.points[ptNum][0] > this.bb[1][0]) { this.bb[1][0] = this.points[ptNum][0]; } if (this.points[ptNum][1] > this.bb[1][1]) { this.bb[1][1] = this.points[ptNum][1]; } if (this.points[ptNum][2] > this.bb[1][2]) { this.bb[1][2] = this.points[ptNum][2]; } } if (hasNorm) { this.compiled.vbo_normals.push(this.faces[faceNum].point_normals[x][0]); this.compiled.vbo_normals.push(this.faces[faceNum].point_normals[x][1]); this.compiled.vbo_normals.push(this.faces[faceNum].point_normals[x][2]); } if (hasUV) { this.compiled.vbo_uvs.push(this.faces[faceNum].uvs[x][0]); this.compiled.vbo_uvs.push(this.faces[faceNum].uvs[x][1]); } if (this.compiled.elements === undef) { this.compiled.elements = []; } if (this.compiled.elements[i] === undef) { this.compiled.elements[i] = []; } if (this.compiled.elements[i][j] === undef) { this.compiled.elements[i][j] = []; } this.compiled.elements[i][j].push(idxCount); if (vtxRef[ptNum] === undef) { vtxRef[ptNum] = []; } vtxRef[ptNum].push([faceNum, x, idxCount]); idxCount++; } } } } } } } this.compiled.gl_points = GLCore.gl.createBuffer(); GLCore.gl.bindBuffer(GLCore.gl.ARRAY_BUFFER, this.compiled.gl_points); GLCore.gl.bufferData(GLCore.gl.ARRAY_BUFFER, new Float32Array(this.compiled.vbo_points), GLCore.gl.STATIC_DRAW); if (hasNorm) { this.compiled.gl_normals = GLCore.gl.createBuffer(); GLCore.gl.bindBuffer(GLCore.gl.ARRAY_BUFFER, this.compiled.gl_normals); GLCore.gl.bufferData(GLCore.gl.ARRAY_BUFFER, new Float32Array(this.compiled.vbo_normals), GLCore.gl.STATIC_DRAW); } else { this.compiled.gl_normals = null; } if (hasUV) { this.compiled.gl_uvs = GLCore.gl.createBuffer(); GLCore.gl.bindBuffer(GLCore.gl.ARRAY_BUFFER, this.compiled.gl_uvs); GLCore.gl.bufferData(GLCore.gl.ARRAY_BUFFER, new Float32Array(this.compiled.vbo_uvs), GLCore.gl.STATIC_DRAW); } else { this.compiled.gl_uvs = null; } var gl_elements = []; this.segment_state = []; this.compiled.elements_ref = []; var ictr = 0; for (i in this.compiled.elements) { if (this.compiled.elements.hasOwnProperty(i)) { this.compiled.elements_ref[ictr] = []; var jctr = 0; for (j in this.compiled.elements[i]) { if (this.compiled.elements[i].hasOwnProperty(j)) { for (k in this.compiled.elements[i][j]) { if (this.compiled.elements[i][j].hasOwnProperty(k)) { gl_elements.push(this.compiled.elements[i][j][k]); } } this.segment_state[j] = true; this.compiled.elements_ref[ictr][jctr] = [parseInt(i), parseInt(j), parseInt(this.compiled.elements[i][j].length)]; jctr++; } } ictr++; } } this.compiled.gl_elements = GLCore.gl.createBuffer(); GLCore.gl.bindBuffer(GLCore.gl.ELEMENT_ARRAY_BUFFER, this.compiled.gl_elements); GLCore.gl.bufferData(GLCore.gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(gl_elements), GLCore.gl.STATIC_DRAW); // dump temporary buffers this.compiled.vbo_normals = null; this.compiled.vbo_points = null; this.compiled.vbo_uvs = null; this.compiled.elements = null; GLCore.gl.bindBuffer(GLCore.gl.ELEMENT_ARRAY_BUFFER, null); return this; }; function UVMapper(obj_in) { if (obj_in!==undef) { this.rotation = (obj_in.rotation===undef)?[0, 0, 0]:obj_in.rotation; this.scale = (obj_in.scale===undef)?[1, 1, 1]:obj_in.scale; this.center = (obj_in.center===undef)?[0, 0, 0]:obj_in.center; this.projection_mode = (obj_in.projectionMode===undef)?enums.uv.projection.PLANAR:obj_in.projectionMode; this.projection_axis = (obj_in.projectionAxis===undef)?enums.uv.axis.X:obj_in.projectionAxis; this.wrap_w_count = (obj_in.wrapW===undef)?1:obj_in.wrapW; this.wrap_h_count = (obj_in.wrapH===undef)?1:obj_in.wrapH; } else { this.rotation = [0, 0, 0]; this.scale = [1, 1, 1]; this.center = [0, 0, 0]; this.projection_mode = enums.uv.projection.PLANAR; this.projection_axis = enums.uv.axis.X; this.wrap_w_count = 1; this.wrap_h_count = 1; } } UVMapper.prototype.setRotation = function(rotation) { this.rotation = rotation; } UVMapper.prototype.setScale = function(scale) { this.scale = scale; } UVMapper.prototype.setCenter = function(center) { this.center = center; } UVMapper.prototype.setProjectionAxis = function(projection_axis) { this.projection_axis = projection_axis; } UVMapper.prototype.setProjectionMode = function(projection_mode) { this.projection_mode = projection_mode; } UVMapper.prototype.setWrapW = function(wrap_w) { this.wrap_w_count = wrap_w; } UVMapper.prototype.setWrapH = function(wrap_h) { this.wrap_h_count = wrap_h; } // convert XYZ space to longitude var xyz_to_h = function(x, y, z) { var h; if (x === 0 && z === 0) { h = 0; } else { if (z === 0) { h = (x < 0) ? M_HALF_PI : -M_HALF_PI; } else if (z < 0) { h = -Math.atan(x / z) + M_PI; } else { h = -Math.atan(x / z); } } return h; }; // convert XYZ space to latitude and longitude var xyz_to_hp = function(x, y, z) { var h, p; if (x === 0 && z === 0) { h = 0; if (y !== 0) { p = (y < 0) ? -M_HALF_PI : M_HALF_PI; } else { p = 0; } } else { if (z === 0) { h = (x < 0) ? M_HALF_PI : -M_HALF_PI; } else if (z < 0) { h = -Math.atan(x / z) + M_PI; } else { h = -Math.atan(x / z); } x = Math.sqrt(x * x + z * z); if (x === 0) { p = (y < 0) ? -M_HALF_PI : M_HALF_PI; } else { p = Math.atan(y / x); } } return [h, p]; }; UVMapper.prototype.apply = function(obj, mat_num, seg_num) { var u, v, s, t, lat, lon; var trans = new Transform(); var transformed = false; var t_result = null; if (this.center[0] || this.center[1] || this.center[2]) { trans.translate(-this.center[0], -this.center[1], -this.center[2]); transformed = true; } if (this.rotation[0] || this.rotation[1] || this.rotation[2]) { if (this.rotation[0]) { trans.rotate(this.rotation[2], 0, 0, 1); } if (this.rotation[1]) { trans.rotate(this.rotation[1], 0, 1, 0); } if (this.rotation[2]) { trans.rotate(this.rotation[0], 1, 0, 0); } transformed = true; } if (transformed) { t_result = trans.getResult(); } if (typeof(mat_num) === 'object') { mat_num = mat_num.material_id; } for (var i = 0, iMax = obj.faces.length; i < iMax; i++) { if (obj.faces[i].material !== mat_num) { continue; } if (seg_num !== undef) { if (obj.faces[i].segment !== seg_num) { continue; } } var nx, ny, nz; if (this.projection_mode === enums.uv.projection.CUBIC || this.projection_mode === enums.uv.projection.SKY) { nx = Math.abs(obj.faces[i].normal[0]); ny = Math.abs(obj.faces[i].normal[1]); nz = Math.abs(obj.faces[i].normal[2]); } for (var j = 0, jMax = obj.faces[i].points.length; j < jMax; j++) { var uvpoint = obj.points[obj.faces[i].points[j]]; if (transformed) { uvpoint = mat4.vec3_multiply(uvpoint, t_result); } /* calculate the uv for the points referenced by this face's pointref vector */ var p_mode = this.projection_mode; //switch (this.projection_mode) { if (p_mode === enums.uv.projection.SKY) { //case enums.uv.projection.SKY: var mapping = obj.sky_mapping; /* see enums.uv.projection.CUBIC for normalization reasoning */ if (nx >= ny && nx >= nz) { s = uvpoint[2] / (this.scale[2]) + this.scale[2] / 2; t = -uvpoint[1] / (this.scale[1]) + this.scale[1] / 2; if (obj.faces[i].normal[0] < 0) { //left s = (mapping[2][2] - mapping[2][0]) * (1-s); t = 1-((mapping[2][3] - mapping[2][1]) * (t)); s += mapping[2][0]; t += mapping[2][1]; } else { //right s = (mapping[3][2] - mapping[3][0]) * (s); t = 1-((mapping[3][3] - mapping[3][1]) * (t)); s += mapping[3][0]; t += mapping[3][1]; } //if } //if if (ny >= nx && ny >= nz) { s = uvpoint[0] / (this.scale[0]) + this.scale[0] / 2; t = -uvpoint[2] / (this.scale[2]) + this.scale[2] / 2; if (obj.faces[i].normal[1] < 0) { //down s = ((mapping[1][2] - mapping[1][0]) * (s)); t = 1-((mapping[1][3] - mapping[1][1]) * (t)); s += mapping[1][0]; t -= mapping[1][1]; } else { //up s = ((mapping[0][2] - mapping[0][0]) * (s)); t = 1-((mapping[0][3] - mapping[0][1]) * (t)); s += mapping[0][0]; t -= mapping[0][1]; } //if } //if if (nz >= nx && nz >= ny) { s = uvpoint[0] / (this.scale[0]) + this.scale[0] / 2; t = uvpoint[1] / (this.scale[1]) + this.scale[1] / 2; if (obj.faces[i].normal[2] < 0) { //front s = ((mapping[4][2] - mapping[4][0]) * (s)); t = 1-((mapping[4][3] - mapping[4][1]) * (1-t)); s += mapping[4][0]; t -= mapping[4][1]; } else { //back s = ((mapping[5][2] - mapping[5][0]) * (1-s)); t = 1-((mapping[5][3] - mapping[5][1]) * (1-t)); s += mapping[5][0]; t += mapping[5][1]; } //if } //if obj.faces[i].setUV([s, t], j); //break; } else if (p_mode === enums.uv.projection.CUBIC) { //case enums.uv.projection.CUBIC: /* cubic projection needs to know the surface normal */ /* x portion of vector is dominant, we're mapping in the Y/Z plane */ if (nx >= ny && nx >= nz) { /* we use a .5 offset because texture coordinates range from 0->1, so to center it we need to offset by .5 */ s = uvpoint[2] / this.scale[2] + 0.5; /* account for scale here */ t = uvpoint[1] / this.scale[1] + 0.5; } /* y portion of vector is dominant, we're mapping in the X/Z plane */ if (ny >= nx && ny >= nz) { s = -uvpoint[0] / this.scale[0] + 0.5; t = uvpoint[2] / this.scale[2] + 0.5; } /* z portion of vector is dominant, we're mapping in the X/Y plane */ if (nz >= nx && nz >= ny) { s = -uvpoint[0] / this.scale[0] + 0.5; t = uvpoint[1] / this.scale[1] + 0.5; } if (obj.faces[i].normal[0] > 0) { s = -s; } if (obj.faces[i].normal[1] < 0) { s = -s; } if (obj.faces[i].normal[2] > 0) { s = -s; } obj.faces[i].setUV([s, t], j); //break; } else if (p_mode === enums.uv.projection.PLANAR) { //case enums.uv.projection.PLANAR: s = ((this.projection_axis === enums.uv.axis.X) ? uvpoint[2] / this.scale[2] + 0.5 : -uvpoint[0] / this.scale[0] + 0.5); t = ((this.projection_axis === enums.uv.axis.Y) ? uvpoint[2] / this.scale[2] + 0.5 : uvpoint[1] / this.scale[1] + 0.5); obj.faces[i].setUV([s, t], j); //break; } else if (p_mode === enums.uv.projection.CYLINDRICAL) { //case enums.uv.projection.CYLINDRICAL: // Cylindrical is a little more tricky, we map based on the degree around the center point var p_axis = this.projection_axis; //switch (this.projection_axis) { if (p_axis === enums.uv.axis.X) { //case enums.uv.axis.X: // xyz_to_h takes the point and returns a value representing the 'unwrapped' height position of this point lon = xyz_to_h(uvpoint[2], uvpoint[0], -uvpoint[1]); t = -uvpoint[0] / this.scale[0] + 0.5; //break; } else if (p_axis === enums.uv.axis.Y) { //case enums.uv.axis.Y: lon = xyz_to_h(-uvpoint[0], uvpoint[1], uvpoint[2]); t = -uvpoint[1] / this.scale[1] + 0.5; //break; } else if (p_axis === enums.uv.axis.Z) { //case enums.uv.axis.Z: lon = xyz_to_h(-uvpoint[0], uvpoint[2], -uvpoint[1]); t = -uvpoint[2] / this.scale[2] + 0.5; //break; } //if // convert it from radian space to texture space 0 to 1 * wrap, TWO_PI = 360 degrees lon = 1.0 - lon / (M_TWO_PI); if (this.wrap_w_count !== 1.0) { lon = lon * this.wrap_w_count; } u = lon; v = t; obj.faces[i].setUV([u, v], j); //break; } else if (p_mode === enums.uv.projection.SPHERICAL) { //case enums.uv.projection.SPHERICAL: var latlon; // spherical is similar to cylindrical except we also unwrap the 'width' var p_axis = this.projection_axis; //switch (this.projection_axis) { if (p_axis === enums.uv.axis.X) { //case enums.uv.axis.X: // xyz to hp takes the point value and 'unwraps' the latitude and longitude that projects to that point latlon = xyz_to_hp(uvpoint[2], uvpoint[0], -uvpoint[1]); //break; } else if (p_axis === enums.uv.axis.Y) { //case enums.uv.axis.Y: latlon = xyz_to_hp(uvpoint[0], -uvpoint[1], uvpoint[2]); //break; } else if (p_axis === enums.uv.axis.Z) { //case enums.uv.axis.Z: latlon = xyz_to_hp(-uvpoint[0], uvpoint[2], -uvpoint[1]); //break; } //if // convert longitude and latitude to texture space coordinates, multiply by wrap height and width lon = 1.0 - latlon[0] / M_TWO_PI; lat = 0.5 - latlon[1] / M_PI; if (this.wrap_w_count !== 1.0) { lon = lon * this.wrap_w_count; } if (this.wrap_h_count !== 1.0) { lat = lat * this.wrap_h_count; } u = lon; v = lat; obj.faces[i].setUV([u, v], j); //break; } else { // case enums.uv.projection.UV: // // not handled here.. // break; //default: // else mapping cannot be handled here, this shouldn't have happened :P u = 0; v = 0; obj.faces[i].setUV([u, v], j); //break; } //if } //for } //for - faces return this; }; function AABB_size(aabb) { var x = aabb[0][0] < aabb[1][0] ? aabb[1][0] - aabb[0][0] : aabb[0][0] - aabb[1][0]; var y = aabb[0][1] < aabb[1][1] ? aabb[1][1] - aabb[0][1] : aabb[0][1] - aabb[1][1]; var z = aabb[0][2] < aabb[1][2] ? aabb[1][2] - aabb[0][2] : aabb[0][2] - aabb[1][2]; return [x,y,z]; } //AABB_size function AABB_reset(aabb, point) { if (point === undefined) { point = [0,0,0]; } //if aabb[0][0] = point[0]; aabb[0][1] = point[1]; aabb[0][2] = point[2]; aabb[1][0] = point[0]; aabb[1][1] = point[1]; aabb[1][2] = point[2]; } //AABB_reset function AABB_engulf(aabb, point) { if (aabb[0][0] > point[0]) { aabb[0][0] = point[0]; } if (aabb[0][1] > point[1]) { aabb[0][1] = point[1]; } if (aabb[0][2] > point[2]) { aabb[0][2] = point[2]; } if (aabb[1][0] < point[0]) { aabb[1][0] = point[0]; } if (aabb[1][1] < point[1]) { aabb[1][1] = point[1]; } if (aabb[1][2] < point[2]) { aabb[1][2] = point[2]; } } //AABB::engulf /* Lights */ function Light(light_type, lighting_method) { if (light_type === undef) { light_type = enums.light.type.POINT; } if (lighting_method === undef) { lighting_method = enums.light.method.DYNAMIC; } if (typeof(light_type)=='object') { this.light_type = (light_type.type!==undef)?light_type.type:enums.light.type.POINT; this.diffuse = (light_type.diffuse!==undef)?light_type.diffuse:[1, 1, 1]; this.specular = (light_type.specular!==undef)?light_type.specular:[1.0,1.0,1.0]; this.intensity = (light_type.intensity!==undef)?light_type.intensity:1.0; this.position = (light_type.position!==undef)?light_type.position:[0, 0, 0]; this.direction = (light_type.direction!==undef)?light_type.direction:[0, 0, 0]; this.distance = (light_type.distance!==undef)?light_type.distance:10; this.method = (light_type.method!==undef)?light_type.method:lighting_method; } else { this.light_type = light_type; this.diffuse = [1, 1, 1]; this.specular = [1.0,1.0,1.0]; this.intensity = 1.0; this.position = [0, 0, 0]; this.direction = [0, 0, 0]; this.distance = 10; this.method = lighting_method; } this.trans = new Transform(); this.lposition = [0, 0, 0]; this.tMatrix = this.trans.getResult(); this.dirty = true; this.octree_leaves = []; this.octree_common_root = null; this.octree_aabb = [[0, 0, 0], [0, 0, 0]]; this.ignore_octree = false; this.visible = true; this.culled = true; this.was_culled = true; this.aabb = [[0,0,0],[0,0,0]]; AABB_reset(this.aabb, this.position); this.adjust_octree = SceneObject.prototype.adjust_octree; this.motion = null; } Light.prototype.setType = function(light_type) { this.light_type = type; } Light.prototype.setMethod = function(method) { this.method = method; } Light.prototype.setDiffuse = function(diffuse) { this.diffuse = diffuse; } Light.prototype.setSpecular = function(specular) { this.specular = specular; } Light.prototype.setIntensity = function(intensity) { this.intensity = intensity; } Light.prototype.setPosition = function(position) { this.position = position; } Light.prototype.setDistance = function(distance) { this.distance = distance; } Light.prototype.control = function(controllerId, motionId, value) { if (controllerId === enums.motion.POS) { this.position[motionId] = value; } else if (controllerId === enums.motion.INTENSITY) { this.intensity = value; } // else if (controllerId === enums.motion.ROT) { // this.rotation[motionId] = value; // } } Light.prototype.doTransform = function(mat) { if (!vec3.equal(this.lposition, this.position) || (mat !== undef)) { this.trans.clearStack(); this.trans.translate(this.position); if ((mat !== undef)) { this.trans.pushMatrix(mat); } this.tMatrix = this.trans.getResult(); this.lposition[0] = this.position[0]; this.lposition[1] = this.position[1]; this.lposition[2] = this.position[2]; this.dirty = true; this.adjust_octree(); } //if } //Light::doTransform Light.prototype.getAABB = function() { var aabb = [[0, 0, 0], [0, 0, 0]]; AABB_engulf(aabb, [this.distance, this.distance, this.distance]); AABB_engulf(aabb, [-this.distance, -this.distance, -this.distance]); aabb[0] = vec3.add(aabb[0], this.position); aabb[1] = vec3.add(aabb[1], this.position); this.aabb = aabb; return this.aabb; }; Light.prototype.setDirection = function(x, y, z) { if (typeof(x) === 'object') { this.setDirection(x[0], x[1], x[2]); return; } this.direction = vec3.normalize([x, y, z]); return this; }; Light.prototype.setRotation = function(x, y, z) { if (typeof(x) === 'object') { this.setRotation(x[0], x[1], x[2]); return; } var t = new Transform(); t.rotate([-x, -y, -z]); t.pushMatrix(); this.direction = vec3.normalize(mat4.vec3_multiply([1, 0, 0], t.getResult())); return this; }; Light.prototype.setupShader = function(lShader,lNum) { // lShader.setVector("lights["+lNum+"].lDiff", this.diffuse); // lShader.setVector("lights["+lNum+"].lSpec", this.specular); // lShader.setFloat("lights["+lNum+"].lInt", this.intensity); // lShader.setFloat("lights["+lNum+"].lDist", this.distance); // lShader.setVector("lights["+lNum+"].lPos", this.position); // lShader.setVector("lights["+lNum+"].lDir", this.direction); var gl = GLCore.gl; gl.uniform3fv(lShader.lights[lNum].lDiff, this.diffuse); gl.uniform3fv(lShader.lights[lNum].lSpec, this.specular); gl.uniform3fv(lShader.lights[lNum].lPos, this.position); gl.uniform3fv(lShader.lights[lNum].lDir, this.direction); gl.uniform1f(lShader.lights[lNum].lInt, this.intensity); gl.uniform1f(lShader.lights[lNum].lDist, this.distance); }; var emptyLight = new Light(enums.light.type.POINT); emptyLight.diffuse = [0, 0, 0]; emptyLight.specular = [0, 0, 0]; emptyLight.distance = 0; emptyLight.intensity = 0; /* Shaders */ function Shader(vs_id, fs_id) { var vertexShader; var fragmentShader; var loadedShader; this.uniforms = []; this.uniform_type = []; this.uniform_typelist = []; if (vs_id.indexOf("\n") !== -1) { vertexShader = cubicvr_compileShader(GLCore.gl, vs_id, "x-shader/x-vertex"); } else { vertexShader = cubicvr_getShader(GLCore.gl, vs_id); if (vertexShader === null) { loadedShader = util.getURL(vs_id); vertexShader = cubicvr_compileShader(GLCore.gl, loadedShader, "x-shader/x-vertex"); } } if (fs_id.indexOf("\n") !== -1) { fragmentShader = cubicvr_compileShader(GLCore.gl, fs_id, "x-shader/x-fragment"); } else { fragmentShader = cubicvr_getShader(GLCore.gl, fs_id); if (fragmentShader === null) { loadedShader = util.getURL(fs_id); fragmentShader = cubicvr_compileShader(GLCore.gl, loadedShader, "x-shader/x-fragment"); } } this.shader = GLCore.gl.createProgram(); GLCore.gl.attachShader(this.shader, vertexShader); GLCore.gl.attachShader(this.shader, fragmentShader); GLCore.gl.linkProgram(this.shader); if (!GLCore.gl.getProgramParameter(this.shader, GLCore.gl.LINK_STATUS)) { // alert("Could not initialise shader vert(" + vs_id + "), frag(" + fs_id + ")"); throw new Error("Could not initialise shader vert(" + vs_id + "), frag(" + fs_id + ")"); return; } } Shader.prototype.bindSelf = function(uniform_id) { var t,k,p,v; if (uniform_id.indexOf(".")!==-1) { if (uniform_id.indexOf("[")!==-1) { t = uniform_id.split("["); p = t[0]; t = t[1].split("]"); k = t[0]; t = t[1].split("."); v = t[1]; if (this[p] === undef) { this[p] = []; } if (this[p][k] === undef) { this[p][k] = {}; } this[p][k][v] = this.uniforms[uniform_id]; } else { // untested t = uniform_id.split("."); p = t[0]; v = t[1]; if (this[p] === undef) { this[p] = {}; } this[p][v] = this.uniforms[uniform_id]; } } else if ( uniform_id.indexOf("[") !== -1){ // untested t = uniform_id.split("["); p = t[0]; t = t[1].split("]"); k = t[0]; if (this[p] === undef) { this[p] = []; } this[p][k] = this.uniforms[uniform_id]; } else { this[uniform_id] = this.uniforms[uniform_id]; } } Shader.prototype.addMatrix = function(uniform_id, default_val) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getUniformLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.MATRIX; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); if (default_val !== undef) { this.setMatrix(uniform_id, default_val); } this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addVector = function(uniform_id, default_val) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getUniformLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.VECTOR; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); if (default_val !== undef) { this.setVector(uniform_id, default_val); } this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addFloat = function(uniform_id, default_val) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getUniformLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.FLOAT; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); if (default_val !== undef) { this.setFloat(uniform_id, default_val); } this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addVertexArray = function(uniform_id) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getAttribLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.ARRAY_VERTEX; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addUVArray = function(uniform_id) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getAttribLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.ARRAY_UV; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addFloatArray = function(uniform_id) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getAttribLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.ARRAY_FLOAT; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.addInt = function(uniform_id, default_val) { this.use(); this.uniforms[uniform_id] = GLCore.gl.getUniformLocation(this.shader, uniform_id); this.uniform_type[uniform_id] = enums.shader.uniform.INT; this.uniform_typelist.push([this.uniforms[uniform_id], this.uniform_type[uniform_id]]); if (default_val !== undef) { this.setInt(uniform_id, default_val); } this.bindSelf(uniform_id); return this.uniforms[uniform_id]; }; Shader.prototype.use = function() { GLCore.gl.useProgram(this.shader); }; Shader.prototype.setMatrix = function(uniform_id, mat) { var u = this.uniforms[uniform_id]; if (u === null) { return; } var l = mat.length; if (l===16) { GLCore.gl.uniformMatrix4fv(u, false, mat); } else if (l === 9) { GLCore.gl.uniformMatrix3fv(u, false, mat); } else if (l === 4) { GLCore.gl.uniformMatrix2fv(u, false, mat); } }; Shader.prototype.setInt = function(uniform_id, val) { var u = this.uniforms[uniform_id]; if (u === null) { return; } GLCore.gl.uniform1i(u, val); }; Shader.prototype.setFloat = function(uniform_id, val) { var u = this.uniforms[uniform_id]; if (u === null) { return; } GLCore.gl.uniform1f(u, val); }; Shader.prototype.setVector = function(uniform_id, val) { var u = this.uniforms[uniform_id]; if (u === null) { return; } var l = val.length; if (l==3) { GLCore.gl.uniform3fv(u, val); } else if (l==2) { GLCore.gl.uniform2fv(u, val); } else { GLCore.gl.uniform4fv(u, val); } }; Shader.prototype.clearArray = function(uniform_id) { var gl = GLCore.gl; var u = this.uniforms[uniform_id]; if (u === null) { return; } gl.disableVertexAttribArray(u); }; Shader.prototype.bindArray = function(uniform_id, buf) { var gl = GLCore.gl; var u = this.uniforms[uniform_id]; if (u === null) { return; } var t = this.uniform_type[uniform_id]; if (t === enums.shader.uniform.ARRAY_VERTEX) { gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.vertexAttribPointer(u, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(u); } else if (t === enums.shader.uniform.ARRAY_UV) { gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.vertexAttribPointer(u, 2, gl.FLOAT, false, 0, 0); } else if (t === enums.shader.uniform.ARRAY_FLOAT) { gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.vertexAttribPointer(u, 1, gl.FLOAT, false, 0, 0); } }; /* Materials */ var Material = function(mat_name) { this.material_id = -1; /* if (mat_name !== undef) { var old_mat = Material_ref[mat_name]; if (old_mat) { var old_id = old_mat.material_id; Materials[old_id] = this; old_mat = null; } //if Material_ref[mat_name] = this; } */ //if (this.material_id === -1) { this.material_id = Materials.length; Materials.push(this); //} //if this.initialized = false; this.textures = []; this.shader = []; this.customShader = null; if (typeof(mat_name)==='object') { this.diffuse = (mat_name.diffuse===undef)?[1.0, 1.0, 1.0]:mat_name.diffuse; this.specular = (mat_name.specular===undef)?[0.1, 0.1, 0.1]:mat_name.specular; this.color = (mat_name.color===undef)?[1, 1, 1]:mat_name.color; this.ambient = (mat_name.ambient===undef)?[0, 0, 0]:mat_name.ambient; this.opacity = (mat_name.opacity===undef)?1.0:mat_name.opacity; this.shininess = (mat_name.shininess===undef)?1.0:mat_name.shininess; this.max_smooth = (mat_name.max_smooth===undef)?60.0:mat_name.max_smooth; this.env_amount = (mat_name.env_amount===undef)?0.75:mat_name.env_amount; this.name = (mat_name.name===undef)?undef:mat_name.name; if (typeof(mat_name.textures)==='object') { if (mat_name.textures.color!==undef) this.setTexture(mat_name.textures.color,enums.texture.map.COLOR); if (mat_name.textures.envsphere!==undef) this.setTexture(mat_name.textures.envsphere,enums.texture.map.ENVSPHERE); if (mat_name.textures.normal!==undef) this.setTexture(mat_name.textures.normal,enums.texture.map.NORMAL); if (mat_name.textures.bump!==undef) this.setTexture(mat_name.textures.bump,enums.texture.map.BUMP); if (mat_name.textures.reflect!==undef) this.setTexture(mat_name.textures.reflect,enums.texture.map.REFLECT); if (mat_name.textures.specular!==undef) this.setTexture(mat_name.textures.specular,enums.texture.map.SPECULAR); if (mat_name.textures.ambient!==undef) this.setTexture(mat_name.textures.ambient,enums.texture.map.AMBIENT); if (mat_name.textures.alpha!==undef) this.setTexture(mat_name.textures.alpha,enums.texture.map.ALPHA); } } else { this.diffuse = [1.0, 1.0, 1.0]; this.specular = [0.1, 0.1, 0.1]; this.color = [1, 1, 1]; this.ambient = [0, 0, 0]; this.opacity = 1.0; this.shininess = 1.0; this.max_smooth = 60.0; this.name = mat_name; } }; Material.prototype.setTexture = function(tex, tex_type) { if (tex_type === undef) { tex_type = 0; } this.textures[tex_type] = tex; }; Material.prototype.calcShaderMask = function() { var shader_mask = 0; shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.COLOR]) === 'object') ? enums.shader.map.COLOR : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.SPECULAR]) === 'object') ? enums.shader.map.SPECULAR : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.NORMAL]) === 'object') ? enums.shader.map.NORMAL : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.BUMP]) === 'object') ? enums.shader.map.BUMP : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.REFLECT]) === 'object') ? enums.shader.map.REFLECT : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.ENVSPHERE]) === 'object') ? enums.shader.map.ENVSPHERE : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.AMBIENT]) === 'object') ? enums.shader.map.AMBIENT : 0); shader_mask = shader_mask + ((typeof(this.textures[enums.texture.map.ALPHA]) === 'object') ? enums.shader.map.ALPHA : 0); shader_mask = shader_mask + ((this.opacity !== 1.0) ? enums.shader.map.ALPHA : 0); return shader_mask; }; Material.prototype.getShaderHeader = function(light_type,light_count) { return ((light_count !== undef) ? ("#define loopCount "+light_count+"\n"):"") + "#define hasColorMap " + ((typeof(this.textures[enums.texture.map.COLOR]) === 'object') ? 1 : 0) + "\n#define hasSpecularMap " + ((typeof(this.textures[enums.texture.map.SPECULAR]) === 'object') ? 1 : 0) + "\n#define hasNormalMap " + ((typeof(this.textures[enums.texture.map.NORMAL]) === 'object') ? 1 : 0) + "\n#define hasBumpMap " + ((typeof(this.textures[enums.texture.map.BUMP]) === 'object') ? 1 : 0) + "\n#define hasReflectMap " + ((typeof(this.textures[enums.texture.map.REFLECT]) === 'object') ? 1 : 0) + "\n#define hasEnvSphereMap " + ((typeof(this.textures[enums.texture.map.ENVSPHERE]) === 'object') ? 1 : 0) + "\n#define hasAmbientMap " + ((typeof(this.textures[enums.texture.map.AMBIENT]) === 'object') ? 1 : 0) + "\n#define hasAlphaMap " + ((typeof(this.textures[enums.texture.map.ALPHA]) === 'object') ? 1 : 0) + "\n#define hasAlpha " + ((this.opacity !== 1.0) ? 1 : 0) + "\n#define lightPoint " + ((light_type === enums.light.type.POINT) ? 1 : 0) + "\n#define lightDirectional " + ((light_type === enums.light.type.DIRECTIONAL) ? 1 : 0) + "\n#define lightSpot " + ((light_type === enums.light.type.SPOT) ? 1 : 0) + "\n#define lightArea " + ((light_type === enums.light.type.AREA) ? 1 : 0) + "\n#define alphaDepth " + (GLCore.depth_alpha ? 1 : 0) + "\n\n"; }; Material.prototype.bindObject = function(obj_in, light_shader) { var gl = GLCore.gl; var u = light_shader; var up = u.aVertexPosition; var uv = u.aTextureCoord; var un = u.aNormal; gl.bindBuffer(gl.ARRAY_BUFFER, obj_in.compiled.gl_points); gl.vertexAttribPointer(up, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(up); if (obj_in.compiled.gl_uvs!==null && uv !==-1) { gl.bindBuffer(gl.ARRAY_BUFFER, obj_in.compiled.gl_uvs); gl.vertexAttribPointer(uv, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(uv); } if (obj_in.compiled.gl_normals!==null && un !==-1) { gl.bindBuffer(gl.ARRAY_BUFFER, obj_in.compiled.gl_normals); gl.vertexAttribPointer(un, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(un); } gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj_in.compiled.gl_elements); }; Material.prototype.clearObject = function(obj_in,light_shader) { var gl = GLCore.gl; var u = light_shader; var uv = u.aTextureCoord; var un = u.aNormal; if (obj_in.compiled.gl_uvs!==null && uv !==-1) { gl.disableVertexAttribArray(uv); } if (obj_in.compiled.gl_normals!==null && un !==-1) { gl.disableVertexAttribArray(un); } } Material.prototype.use = function(light_type,num_lights) { if (num_lights === undef) { num_lights = 0; } if (this.customShader !== null) { this.customShader.use(); return; } if (light_type === undef) { light_type = 0; } var m; var thistex = this.textures; if (this.shader[light_type] === undef) { this.shader[light_type] = []; } if (this.shader[light_type][num_lights] === undef) { var smask = this.calcShaderMask(light_type); if (ShaderPool[light_type][smask] === undef) { ShaderPool[light_type][smask] = []; } if (ShaderPool[light_type][smask][num_lights] === undef) { var hdr = this.getShaderHeader(light_type,num_lights); var vs = hdr + GLCore.CoreShader_vs; var fs = hdr + GLCore.CoreShader_fs; var l = new Shader(vs, fs); ShaderPool[light_type][smask][num_lights] = l; m = 0; if (typeof(thistex[enums.texture.map.COLOR]) === 'object') { l.addInt("colorMap", m++); } if (typeof(thistex[enums.texture.map.ENVSPHERE]) === 'object') { l.addInt("envSphereMap", m++); } if (typeof(thistex[enums.texture.map.NORMAL]) === 'object') { l.addInt("normalMap", m++); } if (typeof(thistex[enums.texture.map.BUMP]) === 'object') { l.addInt("bumpMap", m++); } if (typeof(thistex[enums.texture.map.REFLECT]) === 'object') { l.addInt("reflectMap", m++); } if (typeof(thistex[enums.texture.map.SPECULAR]) === 'object') { l.addInt("specularMap", m++); } if (typeof(thistex[enums.texture.map.AMBIENT]) === 'object') { l.addInt("ambientMap", m++); } if (typeof(thistex[enums.texture.map.ALPHA]) === 'object') { l.addInt("alphaMap", m++); } l.addMatrix("uMVMatrix"); l.addMatrix("uPMatrix"); l.addMatrix("uOMatrix"); l.addMatrix("uNMatrix"); l.addVertexArray("aVertexPosition"); l.addVertexArray("aNormal"); for (var mLight = 0; mLight < num_lights; mLight++) { l.addVector("lights["+mLight+"].lDiff"); l.addVector("lights["+mLight+"].lSpec"); l.addFloat("lights["+mLight+"].lInt"); l.addFloat("lights["+mLight+"].lDist"); l.addVector("lights["+mLight+"].lPos"); l.addVector("lights["+mLight+"].lDir"); } l.addVector("lAmb"); l.addVector("mDiff"); l.addVector("mColor"); l.addVector("mAmb"); l.addVector("mSpec"); l.addFloat("mShine"); l.addFloat("mAlpha"); l.addFloat("envAmount"); if (GLCore.depth_alpha) { l.addVector("depthInfo"); } l.addUVArray("aTextureCoord"); } this.shader[light_type][num_lights] = ShaderPool[light_type][smask][num_lights]; } var sh = this.shader[light_type][num_lights]; var gl = GLCore.gl sh.use(); m = 0; var t; if (t = thistex[enums.texture.map.COLOR]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.ENVSPHERE]) { t.use(GLCore.gl.TEXTURE0+m); m++; // sh.setFloat("envAmount", this.env_amount); gl.uniform1f(sh.envAmount,this.env_amount); } if (t = thistex[enums.texture.map.NORMAL]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.BUMP]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.REFLECT]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.SPECULAR]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.AMBIENT]) { t.use(GLCore.gl.TEXTURE0+m); m++; } if (t = thistex[enums.texture.map.ALPHA]) { t.use(GLCore.gl.TEXTURE0+m); m++; } // sh.setVector("mColor", this.color); // sh.setVector("mDiff", this.diffuse); // sh.setVector("mAmb", this.ambient); // sh.setVector("mSpec", this.specular); // sh.setFloat("mShine", this.shininess); // sh.setVector("lAmb", CubicVR.globalAmbient); gl.uniform3fv(sh.mColor,this.color); gl.uniform3fv(sh.mDiff,this.diffuse); gl.uniform3fv(sh.mAmb,this.ambient); gl.uniform3fv(sh.mSpec,this.specular); gl.uniform1f(sh.mShine,this.shininess*128.0); gl.uniform3fv(sh.lAmb, CubicVR.globalAmbient); if (GLCore.depth_alpha) { //sh.setVector("depthInfo", [GLCore.depth_alpha_near, GLCore.depth_alpha_far, 0.0]); gl.uniform3fv(sh.depthInfo, [GLCore.depth_alpha_near, GLCore.depth_alpha_far, 0.0]); } if (this.opacity !== 1.0) { gl.uniform1f(sh.mAlpha, this.opacity); } }; /* Textures */ var DeferredLoadTexture = function(img_path, filter_type) { this.img_path = img_path; this.filter_type = filter_type; } //DefferedLoadTexture DeferredLoadTexture.prototype.getTexture = function(deferred_bin, binId) { return new Texture(this.img_path, this.filter_type, deferred_bin, binId); } //getTexture var Texture = function(img_path,filter_type,deferred_bin,binId,ready_func) { var gl = GLCore.gl; this.tex_id = Textures.length; this.filterType = -1; this.onready = ready_func; this.loaded = false; Textures[this.tex_id] = gl.createTexture(); Textures_obj[this.tex_id] = this; if (img_path) { Images[this.tex_id] = new Image(); Texture_ref[img_path] = this.tex_id; } gl.bindTexture(gl.TEXTURE_2D, Textures[this.tex_id]); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); if (img_path) { var texId = this.tex_id; var filterType = (filter_type!==undef)?filter_type:GLCore.default_filter; var that = this; Images[this.tex_id].onload = function() { gl.bindTexture(gl.TEXTURE_2D, Textures[texId]); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); var img = Images[texId]; gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); var tw = img.width, th = img.height; var isPOT = true; if (tw===1||th===1) { isPOT = false; } else { if (tw!==1) { while ((tw % 2) === 0) { tw /= 2; } } if (th!==1) { while ((th % 2) === 0) { th /= 2; } } if (tw>1) { isPOT = false; } if (th>1) { isPOT = false; } } if (!isPOT) { 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); } if (Textures_obj[texId].filterType===-1) { if (!isPOT) { if (filterType === enums.texture.filter.LINEAR_MIP) { filterType = enums.texture.filter.LINEAR; } } if (Textures_obj[texId].filterType===-1) { Textures_obj[texId].setFilter(filterType); } } else { Textures_obj[texId].setFilter(Textures_obj[texId].filterType); } gl.bindTexture(gl.TEXTURE_2D, null); if (that.onready) { that.onready(); } //if that.loaded = true; }; if (!deferred_bin) { Images[this.tex_id].src = img_path; } else { Images[this.tex_id].deferredSrc = img_path; //console.log('adding image to binId=' + binId + ' img_path=' + img_path); deferred_bin.addImage(binId,img_path,Images[this.tex_id]); } } this.active_unit = -1; }; Texture.prototype.setFilter = function(filterType) { var gl = CubicVR.GLCore.gl; gl.bindTexture(gl.TEXTURE_2D, Textures[this.tex_id]); /* switch (filterType) { case enums.texture.filter.LINEAR: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); break; case enums.texture.filter.LINEAR_MIP: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.generateMipmap(gl.TEXTURE_2D); break; case enums.texture.filter.NEAREST: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); break; } */ if (filterType === enums.texture.filter.LINEAR) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); } else if (filterType === enums.texture.filter.LINEAR_MIP) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.generateMipmap(gl.TEXTURE_2D); } else if (filterType === enums.texture.filter.NEAREST) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); } else if (filterType === enums.texture.filter.NEAREST_MIP) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); gl.generateMipmap(gl.TEXTURE_2D); } this.filterType = filterType; }; Texture.prototype.use = function(tex_unit) { GLCore.gl.activeTexture(tex_unit); GLCore.gl.bindTexture(GLCore.gl.TEXTURE_2D, Textures[this.tex_id]); this.active_unit = tex_unit; }; Texture.prototype.clear = function() { if (this.active_unit !== -1) { GLCore.gl.activeTexture(this.active_unit); GLCore.gl.bindTexture(GLCore.gl.TEXTURE_2D, null); this.active_unit = -1; } }; function CanvasTexture(canvasElement) { var gl = CubicVR.GLCore.gl; this.canvasSource = canvasElement; this.texture = new CubicVR.Texture(); }; //CanvasTexture CanvasTexture.prototype.use = function(tex_unit) { this.texture.use(tex_unit); }; //CanvasTexture.use CanvasTexture.prototype.setFilter = function(filterType) { this.texture.setFilter(filterType); }; //CanvasTexture.setFilter CanvasTexture.prototype.clear = function() { this.texture.clear(); }; //CanvasTexture.clear CanvasTexture.prototype.update = function() { var gl = CubicVR.GLCore.gl; gl.bindTexture(gl.TEXTURE_2D, CubicVR.Textures[this.texture.tex_id]); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvasSource); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 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.bindTexture(gl.TEXTURE_2D, null); }; //CanvasTexture.update function TextTexture(text, options) { var color = (options && options.color) || '#fff'; var bgcolor = (options && options.bgcolor); var font = (options && options.font) || '18pt Arial'; var align = (options && options.align) || 'start'; var y = (options && options.y) || 0; var width = (options && options.width) || undef; var height = (options && options.height) || undef; var canvas = document.createElement('CANVAS'); var ctx = canvas.getContext('2d'); var lines = 0; if (typeof(text) === 'string') { lines = 1; } else { lines = text.length; } //if ctx.font = font; // This approximation is awful. There has to be a better way to find the height of a text block var lineHeight = (options && options.lineHeight) || ctx.measureText('OO').width; var widest; if (lines === 1) { widest = ctx.measureText(text).width; } else { widest = 0; for (var i=0; i widest) { widest = w; } //if } //for } //if canvas.width = width || widest; canvas.height = height || lineHeight * lines; if (bgcolor) { ctx.fillStyle = bgcolor; ctx.fillRect(0, 0, canvas.width, canvas.height); } //if ctx.fillStyle = color; ctx.font = font; ctx.textAlign = align; ctx.textBaseline = 'top'; if (lines === 1) { var x = (options && options.x) || align === 'center' ? canvas.width/2 : align === 'right' ? canvas.width : 0; ctx.fillText(text, x, y); } else { for (var i=0; i 1) { isPOT = false; } if (th > 1) { isPOT = false; } } // bind functions to "subclass" a texture this.setFilter=this.texture.setFilter; this.clear=this.texture.clear; this.use=this.texture.use; this.tex_id=this.texture.tex_id; this.filterType=this.texture.filterType; if (!isPOT) { this.setFilter(enums.texture.filter.LINEAR); 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); } else { this.setFilter(enums.texture.filter.LINEAR_MIP); } } PJSTexture.prototype.update = function() { var gl = CubicVR.GLCore.gl; this.pjs.redraw(); gl.bindTexture(gl.TEXTURE_2D, CubicVR.Textures[this.texture.tex_id]); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas); if (this.filterType === enums.texture.filter.LINEAR_MIP) { gl.generateMipmap(gl.TEXTURE_2D); } gl.bindTexture(gl.TEXTURE_2D, null); }; /* Render functions */ function cubicvr_renderObject(obj_in,camera,o_matrix,lighting) { if (obj_in.compiled===null) { return; } var ofs = 0; var gl = CubicVR.GLCore.gl; var numLights = (lighting === undef) ? 0: lighting.length; var mshader, last_ltype, l; var lcount = 0; var j; var mat = null; // var nullAmbient = [0,0,0]; // var tmpAmbient = CubicVR.globalAmbient; var bound = false; gl.depthFunc(gl.LEQUAL); if (o_matrix === undef) { o_matrix = cubicvr_identity; } for (var ic = 0, icLen = obj_in.compiled.elements_ref.length; ic < icLen; ic++) { var i = obj_in.compiled.elements_ref[ic][0][0]; mat = Materials[i]; var len = 0; var drawn = false; if (mat.opacity !== 1.0) { gl.enable(gl.BLEND); gl.depthMask(0); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); } else { gl.depthMask(1); gl.disable(gl.BLEND); gl.blendFunc(gl.ONE,gl.ONE); } for (var jc = 0, jcLen = obj_in.compiled.elements_ref[ic].length; jc < jcLen; jc++) { j = obj_in.compiled.elements_ref[ic][jc][1]; drawn = false; var this_len = obj_in.compiled.elements_ref[ic][jc][2]; len += this_len; if (obj_in.segment_state[j]) { // ... } else if (len > this_len) { ofs += this_len*2; len -= this_len; // start lighting loop // start inner if (!numLights) { mat.use(0,0); gl.uniformMatrix4fv(mat.shader[0][0].uMVMatrix,false,camera.mvMatrix); gl.uniformMatrix4fv(mat.shader[0][0].uPMatrix,false,camera.pMatrix); gl.uniformMatrix4fv(mat.shader[0][0].uOMatrix,false,o_matrix); gl.uniformMatrix3fv(mat.shader[0][0].uNMatrix,false,camera.nMatrix); if (!bound) { mat.bindObject(obj_in,mat.shader[0][0]); bound = true; } gl.drawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, ofs); } else { var subcount = 0; var blended = false; for (subcount = 0; subcount < numLights; ) { nLights = numLights-subcount; if (nLights>MAX_LIGHTS) { nLights=MAX_LIGHTS; } if (subcount>0 && !blended) { gl.enable(gl.BLEND); gl.blendFunc(gl.ONE,gl.ONE); gl.depthFunc(gl.EQUAL); blended = true; } mshader = undef; l = lighting[subcount]; var lt = l.light_type for (lcount = 0; lcount < nLights; lcount++) { if (lighting[lcount+subcount].light_type!=lt) { nLights = lcount; break; } } mat.use(l.light_type,nLights); mshader = mat.shader[l.light_type][nLights]; gl.uniformMatrix4fv(mshader.uMVMatrix,false,camera.mvMatrix); gl.uniformMatrix4fv(mshader.uPMatrix,false,camera.pMatrix); gl.uniformMatrix4fv(mshader.uOMatrix,false,o_matrix); gl.uniformMatrix3fv(mshader.uNMatrix,false,camera.nMatrix); if (!bound) { mat.bindObject(obj_in,mshader); bound = true; } for (lcount = 0; lcount < nLights; lcount++) { lighting[lcount+subcount].setupShader(mshader,lcount); } gl.drawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, ofs); // var err = gl.getError(); // if (err) { // var uv = mshader.uniforms["aTextureCoord"]; // var un = mshader.uniforms["aNormal"]; // console.log(obj_in.compiled.gl_uvs!==null,obj_in.compiled.gl_normals!==null, un, uv, len, ofs, subcount); // // throw new Error('webgl error on mesh: ' + obj_in.name); // } subcount += nLights; } if (blended) { gl.disable(gl.BLEND); gl.depthFunc(gl.LEQUAL); } } /// end inner ofs += len*2; // Note: unsigned short = 2 bytes len = 0; drawn = true; } else { ofs += len*2; len = 0; } } if (!drawn && obj_in.segment_state[j]) { // this is an exact copy/paste of above // start lighting loop // start inner if (!numLights) { mat.use(0,0); gl.uniformMatrix4fv(mat.shader[0][0].uMVMatrix,false,camera.mvMatrix); gl.uniformMatrix4fv(mat.shader[0][0].uPMatrix,false,camera.pMatrix); gl.uniformMatrix4fv(mat.shader[0][0].uOMatrix,false,o_matrix); gl.uniformMatrix3fv(mat.shader[0][0].uNMatrix,false,camera.nMatrix); if (!bound) { mat.bindObject(obj_in,mat.shader[0][0]); bound = true; } gl.drawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, ofs); } else { var subcount = 0; var blended = false; for (subcount = 0; subcount < numLights; ) { nLights = numLights-subcount; if (nLights>MAX_LIGHTS) { nLights=MAX_LIGHTS; } if (subcount>0 && !blended) { gl.enable(gl.BLEND); gl.blendFunc(gl.ONE,gl.ONE); gl.depthFunc(gl.EQUAL); blended = true; } mshader = undef; l = lighting[subcount]; var lt = l.light_type for (lcount = 0; lcount < nLights; lcount++) { if (lighting[lcount+subcount].light_type!=lt) { nLights = lcount; break; } } mat.use(l.light_type,nLights); mshader = mat.shader[l.light_type][nLights]; gl.uniformMatrix4fv(mshader.uMVMatrix,false,camera.mvMatrix); gl.uniformMatrix4fv(mshader.uPMatrix,false,camera.pMatrix); gl.uniformMatrix4fv(mshader.uOMatrix,false,o_matrix); gl.uniformMatrix3fv(mshader.uNMatrix,false,camera.nMatrix); if (!bound) { mat.bindObject(obj_in,mshader); bound = true; } for (lcount = 0; lcount < nLights; lcount++) { lighting[lcount+subcount].setupShader(mshader,lcount); } gl.drawElements(gl.TRIANGLES, len, gl.UNSIGNED_SHORT, ofs); // var err = gl.getError(); // if (err) { // var uv = mshader.uniforms["aTextureCoord"]; // var un = mshader.uniforms["aNormal"]; // console.log(obj_in.compiled.gl_uvs!==null,obj_in.compiled.gl_normals!==null, un, uv, len, ofs, subcount); // // throw new Error('webgl error on mesh: ' + obj_in.name); // } subcount += nLights; } if (blended) { gl.disable(gl.BLEND); gl.depthFunc(gl.LEQUAL); } } /// end inner ofs += len*2; } } if (mat && mshader) { mat.clearObject(obj_in,mshader); } // gl.disableVertexAttribArray(0); // gl.disableVertexAttribArray(2); // gl.disableVertexAttribArray(3); gl.depthMask(1); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); } /* Procedural Objects */ function cubicvr_latheObject(obj_in, pointList, lathe_divisions, material, transform, uvmapper) { var slices = []; var sliceNum; var up = [0, 1, 0]; var right = [1, 0, 0]; var pos = [0, 0, 0]; var pofs = obj_in.points.length; var i, j, jMax, k, kMax; sliceNum = 0; for (i = 0; i < M_TWO_PI; i += (M_TWO_PI / lathe_divisions)) { if (sliceNum === lathe_divisions) { break; } right = [Math.cos(i), 0, Math.sin(i)]; for (j = 0, jMax = pointList.length; j < jMax; j++) { pos = vec3.add(vec3.multiply(right, pointList[j][0]), vec3.multiply(up, pointList[j][1])); if (slices[sliceNum] === undef) { slices[sliceNum] = []; } slices[sliceNum].push(pos); } sliceNum++; } var m = null; if (transform!==undef) m = (transform.getResult!==undef)?transform.getResult():transform; for (j = 0; j < lathe_divisions; j++) { for (k = 0, kMax = pointList.length; k < kMax; k++) { if (m) { obj_in.addPoint(mat4.vec3_multiply(slices[j][k], m)); } else { obj_in.addPoint(slices[j][k]); } } } obj_in.setFaceMaterial(material); for (k = 0; k < lathe_divisions; k++) { for (j = 0, jMax = pointList.length - 1; j < jMax; j++) { var pt = j + (pointList.length * k); var pt_r = j + (pointList.length * ((k + 1) % (lathe_divisions))); if (vec3.equal(obj_in.points[pofs + pt], obj_in.points[pofs + pt_r])) { obj_in.addFace([pofs + pt + 1, pofs + pt_r + 1, pofs + pt_r]); } else if (vec3.equal(obj_in.points[pofs + pt + 1], obj_in.points[pofs + pt_r + 1])) { obj_in.addFace([pofs + pt, pofs + pt + 1, pofs + pt_r]); } else { obj_in.addFace([pofs + pt, pofs + pt + 1, pofs + pt_r + 1, pofs + pt_r]); } } } if (uvmapper !== undef) { var uvm = null; if (uvmapper.apply !== undef) { uvm = uvmapper; } else if (uvmapper) { uvm = new UVMapper(uvmapper); } if (uvm !== null) { // Calculate face normals (used for UV mapping and lighting), todo: face range+offset obj_in.calcNormals(); uvm.apply(obj_in, material); } } } function cubicvr_planeObject(mesh, size, mat, transform, uvmapper) { var half_size = size*0.5; var pofs = mesh.points.length; mesh.setFaceMaterial(mat); if (transform !== undef) { var m = (transform.getResult!==undef)?transform.getResult():transform; mesh.addPoint([ mat4.vec3_multiply([half_size, -half_size, 0],m), mat4.vec3_multiply([half_size, half_size, 0],m), mat4.vec3_multiply([-half_size, half_size, 0],m), mat4.vec3_multiply([-half_size, -half_size, 0],m) ]); } else { mesh.addPoint([ [half_size, -half_size, 0], [half_size, half_size, 0], [-half_size, half_size, 0], [-half_size, -half_size, 0] ]); } mesh.addFace([ [pofs+0, pofs+1, pofs+2, pofs+3], //back [pofs+3, pofs+2, pofs+1, pofs+0] //front ]); if (uvmapper !== undef) { var uvm = null; if (uvmapper.apply !== undef) { uvm = uvmapper; } else if (uvmapper) { uvm = new UVMapper(uvmapper); } if (uvm !== null) { // Calculate face normals (used for UV mapping and lighting), todo: face range+offset mesh.calcNormals(); uvm.apply(mesh, mat); } } } //cubicvr_planeObject function cubicvr_boxObject(boxObj, box_size, box_mat, transform, uvmapper) { var half_box = box_size / 2.0; var pofs = boxObj.points.length; boxObj.setFaceMaterial(box_mat); if (transform !== undef) { var m = (transform.getResult!==undef)?transform.getResult():transform; boxObj.addPoint([ mat4.vec3_multiply([half_box, -half_box, half_box], m), mat4.vec3_multiply([half_box, half_box, half_box], m), mat4.vec3_multiply([-half_box, half_box, half_box], m), mat4.vec3_multiply([-half_box, -half_box, half_box], m), mat4.vec3_multiply([half_box, -half_box, -half_box], m), mat4.vec3_multiply([half_box, half_box, -half_box], m), mat4.vec3_multiply([-half_box, half_box, -half_box], m), mat4.vec3_multiply([-half_box, -half_box, -half_box], m) ]); } else { boxObj.addPoint([ [half_box, -half_box, half_box], [half_box, half_box, half_box], [-half_box, half_box, half_box], [-half_box, -half_box, half_box], [half_box, -half_box, -half_box], [half_box, half_box, -half_box], [-half_box, half_box, -half_box], [-half_box, -half_box, -half_box] ]); } boxObj.addFace([ [pofs + 0, pofs + 1, pofs + 2, pofs + 3], [pofs + 7, pofs + 6, pofs + 5, pofs + 4], [pofs + 4, pofs + 5, pofs + 1, pofs + 0], [pofs + 5, pofs + 6, pofs + 2, pofs + 1], [pofs + 6, pofs + 7, pofs + 3, pofs + 2], [pofs + 7, pofs + 4, pofs + 0, pofs + 3] ]); if (uvmapper !== undef) { var uvm = null; if (uvmapper.apply !== undef) { uvm = uvmapper; } else if (uvmapper) { uvm = new UVMapper(uvmapper); } if (uvm !== null) { // Calculate face normals (used for UV mapping and lighting), todo: face range+offset boxObj.calcNormals(); uvm.apply(boxObj, box_mat); } } } function cubicvr_torusObject(mesh, inner_radius, outer_radius, lon, lat, material, transform, uvmapper) { var pointList = new Array(); var thick = outer_radius-inner_radius; var radius = inner_radius+(thick)/2.0; // generate a circle on the right side (radius) of the X/Y axis, circle radius of (thick) var step = (M_TWO_PI / lat); var theta = 0; for (var i = 0; i <= lat; i ++) { pointList.push([radius + Math.cos(theta) * thick, Math.sin(theta) * thick, 0]); theta += step; } CubicVR.genLatheObject(mesh, pointList, lon, material, transform, uvmapper); } function cubicvr_coneObject(mesh, base, height, lon, material, transform, uvmapper) { CubicVR.genLatheObject(mesh, [[0,-height/2,0],[base/2.0,-height/2,0],[0,height/2,0]], lon, material, transform, uvmapper); } function cubicvr_cylinderObject(mesh, radius, height, lon, material, transform, uvmapper) { CubicVR.genLatheObject(mesh, [[0,-height/2,0],[radius,-height/2,0],[radius,height/2,0],[0,height/2,0]], lon, material, transform, uvmapper); } function cubicvr_sphereObject(mesh, radius, lon, lat, material, transform, uvmapper) { var pointList = new Array(); lat = parseInt(lat /= 2); lon = parseInt(lon); // generate a half-circle on the right side of the x/y axis var step = (M_PI / lat); var theta = -M_HALF_PI; for (var i = 0; i <= lat; i ++) { pointList.push([Math.cos(theta) * radius, Math.sin(theta) * radius, 0]); theta += step; } CubicVR.genLatheObject(mesh, pointList, lon, material, transform, uvmapper); } var primitives = { lathe: function(obj_init) { var obj_in, material, transform, uvmapper; var pointList, lathe_divisions; if (obj_init.points==undef) return null; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; lathe_divisions = (obj_init.divisions!==undef)?obj_init.divisions:24; cubicvr_latheObject(obj_in,obj_init.points,lathe_divisions,material,transform,uvmapper); return obj_in; }, box: function(obj_init) { var obj_in, material, transform, uvmapper; var size; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; size = (obj_init.size!==undef)?obj_init.size:1.0; cubicvr_boxObject(obj_in, size, material, transform, uvmapper); return obj_in; }, plane: function(obj_init) { var obj_in, material, transform, uvmapper; var size; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; size = (obj_init.size!==undef)?obj_init.size:1.0; cubicvr_planeObject(obj_in, size, material, transform, uvmapper); return obj_in; }, sphere: function(obj_init) { var obj_in, material, transform, uvmapper; var radius, lon, lat; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; radius = (obj_init.radius!==undef)?obj_init.radius:1.0; lon = (obj_init.lon!==undef)?obj_init.lon:24; lat = (obj_init.lat!==undef)?obj_init.lat:24; cubicvr_sphereObject(obj_in, radius, lon, lat, material, transform, uvmapper); return obj_in; }, torus: function(obj_init) { var obj_in, material, transform, uvmapper; var innerRadius, outerRadius, lon, lat; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; innerRadius = (obj_init.innerRadius!==undef)?obj_init.innerRadius:0.75; outerRadius = (obj_init.outerRadius!==undef)?obj_init.outerRadius:1.0; lon = (obj_init.lon!==undef)?obj_init.lon:24; lat = (obj_init.lat!==undef)?obj_init.lat:24; cubicvr_torusObject(obj_in, innerRadius, outerRadius, lon, lat, material, transform, uvmapper); return obj_in; }, cone: function(obj_init) { var obj_in, material, transform, uvmapper; var base, height, lon; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; base = (obj_init.base!==undef)?obj_init.base:1.0; height = (obj_init.height!==undef)?obj_init.height:1.0; lon = (obj_init.lon!==undef)?obj_init.lon:24; cubicvr_coneObject(obj_in, base, height, lon, material, transform, uvmapper); return obj_in; }, cylinder: function(obj_init) { var obj_in, material, transform, uvmapper; var radius, height; obj_in = (obj_init.mesh!==undef)?obj_init.mesh:(new CubicVR.Mesh((obj_init.name!==undef)?obj_init.name:undef)); material = (obj_init.material!==undef)?obj_init.material:(new CubicVR.Material()); transform = (obj_init.transform!==undef)?obj_init.transform:undef; uvmapper = (obj_init.uvmapper!==undef)?obj_init.uvmapper:undef; radius = (obj_init.radius!==undef)?obj_init.radius:1.0; height = (obj_init.height!==undef)?obj_init.height:1.0; lon = (obj_init.lon!==undef)?obj_init.lon:24; cubicvr_cylinderObject(obj_in, radius, height, lon, material, transform, uvmapper); return obj_in; } } function Landscape(size_in, divisions_in_w, divisions_in_h, matRef_in) { this.doTransform = function() {}; this.tMatrix = cubicvr_identity; this.parent = null; this.position = [0, 0, 0]; this.scale = [1, 1, 1]; this.size = size_in; this.divisions_w = divisions_in_w; this.divisions_h = divisions_in_h; this.matRef = matRef_in; this.children = null; this.obj = new Mesh(); var i, j; if (this.divisions_w > this.divisions_h) { this.size_w = size_in; this.size_h = (size_in / this.divisions_w) * this.divisions_h; } else if (this.divisions_h > this.divisions_w) { this.size_w = (size_in / this.divisions_h) * this.divisions_w; this.size_h = size_in; } else { this.size_w = size_in; this.size_h = size_in; } for (j = -(this.size_h / 2.0); j < (this.size_h / 2.0); j += (this.size_h / this.divisions_h)) { for (i = -(this.size_w / 2.0); i < (this.size_w / 2.0); i += (this.size_w / this.divisions_w)) { this.obj.addPoint([i + ((this.size_w / (this.divisions_w)) / 2.0), 0, j + ((this.size_h / (this.divisions_h)) / 2.0)]); } } var k, l; this.obj.setFaceMaterial(this.matRef); for (l = 0; l < this.divisions_h - 1; l++) { for (k = 0; k < this.divisions_w - 1; k++) { this.obj.addFace([(k) + ((l + 1) * this.divisions_w), (k + 1) + ((l) * this.divisions_w), (k) + ((l) * this.divisions_w)]); this.obj.addFace([(k) + ((l + 1) * this.divisions_w), (k + 1) + ((l + 1) * this.divisions_w), (k + 1) + ((l) * this.divisions_w)]); } } } Landscape.prototype.getMesh = function() { return this.obj; } Landscape.prototype.setIndexedHeight = function(ipos, jpos, val) { obj.points[(ipos) + (jpos * this.divisions_w)][1] = val; } Landscape.prototype.mapGen = function(w_func, ipos, jpos, ilen, jlen) { var pt; if (ipos!==undef && jpos !==undef && ilen !==undef && jlen!==undef) { if (ipos>=this.divisions_w) return; if (jpos>=this.divisions_h) return; if (ipos+ilen>=this.divisions_w) ilen = this.divisions_w-1-ipos; if (jpos+jlen>=this.divisions_h) jlen = this.divisions_h-1-jpos; if (ilen<=0 || jlen<=0) return; for (var i = ipos, imax = ipos+ilen; i < imax; i++) { for (var j = jpos, jmax = jpos+jlen; j < jmax; j++) { pt = this.obj.points[(i) + (j * this.divisions_w)]; pt[1] = w_func(pt[0],pt[2]); } } } else { for (var x = 0, xmax = this.obj.points.length; x < xmax; x++) { pt = this.obj.points[x]; pt[1] = w_func(pt[0],pt[2]); } } } Landscape.prototype.getFaceAt = function(x, z) { if (typeof(x) === 'object') { return this.getFaceAt(x[0], x[2]); } var ofs_w = (this.size_w / 2.0) - ((this.size_w / (this.divisions_w)) / 2.0); var ofs_h = (this.size_h / 2.0) - ((this.size_h / (this.divisions_h)) / 2.0); var i = parseInt(Math.floor(((x + ofs_w) / this.size_w) * (this.divisions_w)), 10); var j = parseInt(Math.floor(((z + ofs_h) / this.size_h) * (this.divisions_h)), 10); if (i < 0) { return -1; } if (i >= this.divisions_w - 1) { return -1; } if (j < 0) { return -1; } if (j >= this.divisions_h - 1) { return -1; } var faceNum1 = parseInt(i + (j * (this.divisions_w - 1)), 10) * 2; var faceNum2 = parseInt(faceNum1 + 1, 10); var testPt = this.obj.points[this.obj.faces[faceNum1].points[0]]; var slope = Math.abs(z - testPt[2]) / Math.abs(x - testPt[0]); if (slope >= 1.0) { return (faceNum1); } else { return (faceNum2); } }; /* cvrFloat Landscape::getHeightValue(XYZ &pt) { Face *tmpFace; XYZ *tmpPoint; int faceNum = getFaceAt(pt); if (faceNum === -1) return 0; tmpFace = obj->faces[faceNum]; tmpPoint = obj->points[obj->faces[faceNum]->pointref[0]]; tmpFace->calcFaceNormal(); cvrFloat na = tmpFace->face_normal.x; cvrFloat nb = tmpFace->face_normal.y; cvrFloat nc = tmpFace->face_normal.z; cvrFloat d = -na * tmpPoint->x - nb * tmpPoint->y - nc * tmpPoint->z; return ((na * pt.x + nc * pt.z+d)/-nb)+getPosition().y; }; */ Landscape.prototype.getHeightValue = function(x, z) { if (typeof(x) === 'object') { return this.getHeightValue(x[0], x[2]); } var tmpFace; var tmpPoint; var faceNum = this.getFaceAt(x, z); if (faceNum === -1) { return 0; } tmpFace = this.obj.faces[faceNum]; tmpPoint = this.obj.points[this.obj.faces[faceNum].points[0]]; var tmpNorm = triangle.normal(this.obj.points[this.obj.faces[faceNum].points[0]], this.obj.points[this.obj.faces[faceNum].points[1]], this.obj.points[this.obj.faces[faceNum].points[2]]); var na = tmpNorm[0]; var nb = tmpNorm[1]; var nc = tmpNorm[2]; var d = -(na * tmpPoint[0]) - (nb * tmpPoint[1]) - (nc * tmpPoint[2]); return (((na * x) + (nc * z) + d) / (-nb)); // add height ofs here }; Landscape.prototype.orient = function(x, z, width, length, heading, center) { if (center === undef) { center = 0; } var xpos, zpos; var xrot, zrot; var heightsample = []; var xyzTmp; var halfw = width / 2.0; var halfl = length / 2.0; var mag = Math.sqrt(halfl * halfl + halfw * halfw); var ang = Math.atan2(halfl, halfw); heading *= (M_PI / 180.0); xpos = x + (Math.sin(heading) * center); zpos = z + (Math.cos(heading) * center); heightsample[0] = this.getHeightValue([xpos + mag * Math.cos(-ang - M_HALF_PI + heading), 0, zpos + mag * -Math.sin(-ang - M_HALF_PI + heading)]); heightsample[1] = this.getHeightValue([xpos + mag * Math.cos(ang - M_HALF_PI + heading), 0, zpos + mag * (-Math.sin(ang - M_HALF_PI + heading))]); heightsample[2] = this.getHeightValue([xpos + mag * Math.cos(-ang + M_HALF_PI + heading), 0, zpos + mag * (-Math.sin(-ang + M_HALF_PI + heading))]); heightsample[3] = this.getHeightValue([xpos + mag * Math.cos(ang + M_HALF_PI + heading), 0, zpos + mag * (-Math.sin(ang + M_HALF_PI + heading))]); xrot = -Math.atan2((heightsample[1] - heightsample[2]), width); zrot = -Math.atan2((heightsample[0] - heightsample[1]), length); xrot += -Math.atan2((heightsample[0] - heightsample[3]), width); zrot += -Math.atan2((heightsample[3] - heightsample[2]), length); xrot /= 2.0; // average angles zrot /= 2.0; return [[x, ((heightsample[2] + heightsample[3] + heightsample[1] + heightsample[0])) / 4.0, z], // [xrot * (180.0 / M_PI), heading, zrot * (180.0 / M_PI)]]; }; var scene_object_uuid = 0; function SceneObject(obj, name) { var obj_init = null; if (obj!==undef && obj!==null) { if (obj.compile) { obj_init = null; } else { obj_init = obj; } } if (obj_init) { this.position = (obj_init.position===undef)?[0, 0, 0]:obj_init.position; this.rotation = (obj_init.rotation===undef)?[0, 0, 0]:obj_init.rotation; this.scale = (obj_init.scale===undef)?[1, 1, 1]:obj_init.scale; this.motion = (obj_init.motion===undef)?null:obj_init.motion; this.obj = (obj_init.mesh===undef)?((obj !== undef && obj_init.faces !== undef) ? obj : null):obj_init.mesh; this.name = (obj_init.name===undef)?((name !== undef) ? name : null):obj_init.name; } else { this.position = [0, 0, 0]; this.rotation = [0, 0, 0]; this.scale = [1, 1, 1]; this.motion = null; this.obj = obj; this.name = name; } this.children = null; this.parent = null; this.drawn_this_frame = false; this.lposition = [0, 0, 0]; this.lrotation = [0, 0, 0]; this.lscale = [0, 0, 0]; this.trans = new Transform(); this.tMatrix = this.trans.getResult(); this.dirty = true; this.aabb = []; this.id = -1; this.octree_leaves = []; this.octree_common_root = null; this.octree_aabb = [[0,0,0],[0,0,0]]; AABB_reset(this.octree_aabb, [0,0,0]); this.ignore_octree = false; this.visible = true; this.culled = true; this.was_culled = true; this.dynamic_lights = []; this.static_lights = []; } SceneObject.prototype.doTransform = function(mat) { if (!vec3.equal(this.lposition, this.position) || !vec3.equal(this.lrotation, this.rotation) || !vec3.equal(this.lscale, this.scale) || (mat !== undef)) { this.trans.clearStack(); if ((mat !== undef)) { this.trans.pushMatrix(mat); } this.trans.translate(this.position); if (! (this.rotation[0] === 0 && this.rotation[1] === 0 && this.rotation[2] === 0)) { this.trans.pushMatrix(); this.trans.rotate(this.rotation); } if (! (this.scale[0] === 1 && this.scale[1] === 1 && this.scale[2] === 1)) { this.trans.pushMatrix(); this.trans.scale(this.scale); } this.tMatrix = this.trans.getResult(); this.lposition[0] = this.position[0]; this.lposition[1] = this.position[1]; this.lposition[2] = this.position[2]; this.lrotation[0] = this.rotation[0]; this.lrotation[1] = this.rotation[1]; this.lrotation[2] = this.rotation[2]; this.lscale[0] = this.scale[0]; this.lscale[1] = this.scale[1]; this.lscale[2] = this.scale[2]; this.dirty = true; } }; SceneObject.prototype.adjust_octree = function() { var aabb = this.getAABB(); var taabb = this.octree_aabb; var px0 = aabb[0][0]; var py0 = aabb[0][1]; var pz0 = aabb[0][2]; var px1 = aabb[1][0]; var py1 = aabb[1][1]; var pz1 = aabb[1][2]; var tx0 = taabb[0][0]; var ty0 = taabb[0][1]; var tz0 = taabb[0][2]; var tx1 = taabb[1][0]; var ty1 = taabb[1][1]; var tz1 = taabb[1][2]; if (this.octree_leaves.length > 0 && (px0 < tx0 || py0 < ty0 || pz0 < tz0 || px1 > tx1 || py1 > ty1 || pz1 > tz1)) { for (var i = 0; i < this.octree_leaves.length; ++i) { this.octree_leaves[i].remove(this); } //for this.octree_leaves = []; this.static_lights = []; var common_root = this.octree_common_root; this.octree_common_root = null; if (common_root !== null) { while (true) { if (!common_root.contains_point(aabb[0]) || !common_root.contains_point(aabb[1])) { if (common_root._root !== undef && common_root._root !== null) { common_root = common_root._root; } else { break; } //if } else { break; } //if } //while AABB_reset(this.octree_aabb, this.position); common_root.insert(this); } //if } //if }; //SceneObject::adjust_octree SceneObject.prototype.bindChild = function(childSceneObj) { if (this.children === null) { this.children = []; } childSceneObj.parent = this; this.children.push(childSceneObj); }; SceneObject.prototype.control = function(controllerId, motionId, value) { if (controllerId === enums.motion.POS) { this.position[motionId] = value; } else if (controllerId === enums.motion.SCL) { this.scale[motionId] = value; } else if (controllerId === enums.motion.ROT) { this.rotation[motionId] = value; } /* switch (controllerId) { case enums.motion.POS: this.position[motionId] = value; break; case enums.motion.SCL: this.scale[motionId] = value; break; case enums.motion.ROT: this.rotation[motionId] = value; break; } */ }; SceneObject.prototype.getAABB = function() { if (this.dirty) { var p = new Array(8); this.doTransform(); var aabbMin; var aabbMax; if (this.obj !== null) { if (this.obj.bb === null) { this.aabb = [vec3.add([-1,-1,-1],this.position),vec3.add([1,1,1],this.position)]; return this.aabb; } aabbMin = this.obj.bb[0]; aabbMax = this.obj.bb[1]; } if (this.obj === null || aabbMin === undef || aabbMax === undef) { // aabbMin=[-1,-1,-1]; // aabbMax=[1,1,1]; // // if (this.obj.bb.length===0) // { this.aabb = [vec3.add([-1,-1,-1],this.position),vec3.add([1,1,1],this.position)]; return this.aabb; // } } /* if (this.scale[0] !== 1 || this.scale[1] !== 1 || this.scale[2] !== 1) { aabbMin[0] *= this.scale[0]; aabbMin[1] *= this.scale[1]; aabbMin[2] *= this.scale[2]; aabbMax[0] *= this.scale[0]; aabbMax[1] *= this.scale[1]; aabbMax[2] *= this.scale[2]; } */ var obj_aabb = aabbMin; var obj_bounds = vec3.subtract(aabbMax, aabbMin); p[0] = [obj_aabb[0], obj_aabb[1], obj_aabb[2]]; p[1] = [obj_aabb[0], obj_aabb[1], obj_aabb[2] + obj_bounds[2]]; p[2] = [obj_aabb[0] + obj_bounds[0], obj_aabb[1], obj_aabb[2]]; p[3] = [obj_aabb[0] + obj_bounds[0], obj_aabb[1], obj_aabb[2] + obj_bounds[2]]; p[4] = [obj_aabb[0], obj_aabb[1] + obj_bounds[1], obj_aabb[2]]; p[5] = [obj_aabb[0], obj_aabb[1] + obj_bounds[1], obj_aabb[2] + obj_bounds[2]]; p[6] = [obj_aabb[0] + obj_bounds[0], obj_aabb[1] + obj_bounds[1], obj_aabb[2]]; p[7] = [obj_aabb[0] + obj_bounds[0], obj_aabb[1] + obj_bounds[1], obj_aabb[2] + obj_bounds[2]]; var aabbTest; aabbTest = mat4.vec3_multiply(p[0], this.tMatrix); aabbMin = [aabbTest[0], aabbTest[1], aabbTest[2]]; aabbMax = [aabbTest[0], aabbTest[1], aabbTest[2]]; for (var i = 1; i < 8; ++i) { aabbTest = mat4.vec3_multiply(p[i], this.tMatrix); if (aabbMin[0] > aabbTest[0]) { aabbMin[0] = aabbTest[0]; } if (aabbMin[1] > aabbTest[1]) { aabbMin[1] = aabbTest[1]; } if (aabbMin[2] > aabbTest[2]) { aabbMin[2] = aabbTest[2]; } if (aabbMax[0] < aabbTest[0]) { aabbMax[0] = aabbTest[0]; } if (aabbMax[1] < aabbTest[1]) { aabbMax[1] = aabbTest[1]; } if (aabbMax[2] < aabbTest[2]) { aabbMax[2] = aabbTest[2]; } } this.aabb[0] = aabbMin; this.aabb[1] = aabbMax; this.dirty = false; } return this.aabb; }; var cubicvr_env_range = function(v, lo, hi) { var v2, i = 0, r; r = hi - lo; if (r === 0.0) { return [lo, 0]; } v2 = v - r * Math.floor((v - lo) / r); i = -parseInt((v2 - v) / r + (v2 > v ? 0.5 : -0.5), 10); return [v2, i]; }; var cubicvr_env_hermite = function(t) { var h1, h2, h3, h4; var t2, t3; t2 = t * t; t3 = t * t2; h2 = 3.0 * t2 - t3 - t3; h1 = 1.0 - h2; h4 = t3 - t2; h3 = h4 - t2 + t; return [h1, h2, h3, h4]; }; var cubicvr_env_bezier = function(x0, x1, x2, x3, t) { var a, b, c, t2, t3; t2 = t * t; t3 = t2 * t; c = 3.0 * (x1 - x0); b = 3.0 * (x2 - x1) - c; a = x3 - x0 - c - b; return a * t3 + b * t2 + c * t + x0; }; var cubicvr_env_bez2_time = function(x0, x1, x2, x3, time, t0, t1) { var v, t; t = t0 + (t1 - t0) * 0.5; v = cubicvr_env_bezier(x0, x1, x2, x3, t); if (Math.abs(time - v) > 0.0001) { if (v > time) { t1 = t; } else { t0 = t; } return cubicvr_env_bez2_time(x0, x1, x2, x3, time, t0, t1); } else { return t; } }; var cubicvr_env_bez2 = function(key0, key1, time) { var x, y, t, t0 = 0.0, t1 = 1.0; if ( key0.shape === enums.envelope.shape.BEZ2 ) { x = key0.time + key0.param[ 2 ]; } else { x = key0.time + ( key1.time - key0.time ) / 3.0; } t = cubicvr_env_bez2_time( key0.time, x, key1.time + key1.param[ 0 ], key1.time, time, t0, t1 ); if ( key0.shape === enums.envelope.shape.BEZ2 ){ y = key0.value + key0.param[ 3 ]; } else { y = key0.value + key0.param[ 1 ] / 3.0; } return cubicvr_env_bezier( key0.value, y, key1.param[ 1 ] + key1.value, key1.value, t ); } var cubicvr_env_outgoing = function(key0, key1) { var a, b, d, t, out; if (key0.shape === enums.envelope.shape.TCB) { a = (1.0 - key0.tension) * (1.0 + key0.continuity) * (1.0 + key0.bias); b = (1.0 - key0.tension) * (1.0 - key0.continuity) * (1.0 - key0.bias); d = key1.value - key0.value; if (key0.prev) { t = (key1.time - key0.time) / (key1.time - (key0.prev).time); out = t * (a * (key0.value - (key0.prev).value) + b * d); } else { out = b * d; } } else if (key0.shape === enums.envelope.shape.LINE) { d = key1.value - key0.value; if (key0.prev) { t = (key1.time - key0.time) / (key1.time - (key0.prev).time); out = t * (key0.value - (key0.prev).value + d); } else { out = d; } } else if ((key0.shape === enums.envelope.shape.BEZI)||(key0.shape === enums.envelope.shape.HERM)) { out = key0.param[1]; if (key0.prev) { out *= (key1.time - key0.time) / (key1.time - (key0.prev).time); } } else if (key0.shape === enums.envelope.shape.BEZ2) { out = key0.param[3] * (key1.time - key0.time); if (Math.abs(key0.param[2]) > 1e-5) { out /= key0.param[2]; } else { out *= 1e5; } } else if (key0.shape === enums.envelope.shape.STEP) { out = 0.0; } else { out = 0.0; } return out; }; var cubicvr_env_incoming = function(key0, key1) { var a, b, d, t, inval; if (key1.shape === enums.envelope.shape.LINE) { d = key1.value - key0.value; if (key1.next) { t = (key1.time - key0.time) / ((key1.next).time - key0.time); inval = t * ((key1.next).value - key1.value + d); } else { inval = d; } } else if (key1.shape === enums.envelope.shape.TCB) { a = (1.0 - key1.tension) * (1.0 - key1.continuity) * (1.0 + key1.bias); b = (1.0 - key1.tension) * (1.0 + key1.continuity) * (1.0 - key1.bias); d = key1.value - key0.value; if (key1.next) { t = (key1.time - key0.time) / ((key1.next).time - key0.time); inval = t * (b * ((key1.next).value - key1.value) + a * d); } else { inval = a * d; } } else if ((key1.shape === enums.envelope.shape.HERM) || (key1.shape === enums.envelope.shape.BEZI)) { inval = key1.param[0]; if (key1.next) { inval *= (key1.time - key0.time) / ((key1.next).time - key0.time); } } else if (key1.shape === enums.envelope.shape.BEZ2) { inval = key1.param[1] * (key1.time - key0.time); if (Math.abs(key1.param[0]) > 1e-5) { inval /= key1.param[0]; } else { inval *= 1e5; } } else if (key1.shape === enums.envelope.shape.STEP) { inval = 0.0; } else { inval = 0.0; } return inval; }; function EnvelopeKey() { this.value = 0; this.time = 0; this.shape = enums.envelope.shape.TCB; this.tension = 0; this.continuity = 0; this.bias = 0; this.prev = null; this.next = null; this.param = [0,0,0,0]; } function Envelope(obj_init) { this.nKeys = 0; this.keys = null; this.firstKey = null; this.lastKey = null; if (obj_init) { this.in_behavior = obj_init.in_behavior?obj_init.in_behavior:enums.envelope.behavior.CONSTANT; this.out_behavior = obj_init.out_behavior?obj_init.out_behavior:enums.envelope.behavior.CONSTANT; } else { this.in_behavior = enums.envelope.behavior.CONSTANT; this.out_behavior = enums.envelope.behavior.CONSTANT; } } Envelope.prototype.setBehavior = function(in_b, out_b) { this.in_behavior = in_b; this.out_behavior = out_b; }; Envelope.prototype.empty = function() { return (this.nKeys === 0); }; Envelope.prototype.addKey = function(time, value, key_init) { var tempKey; var obj = (typeof(time)=='object')?time:key_init; if (!value) value = 0; if (!time) time = 0; if (obj) { obj = time; time = obj.time; tempKey = this.insertKey(time); tempKey.value = obj.value?obj.value:value; tempKey.time = obj.time?obj.time:time;; tempKey.shape = obj.shape?obj.shape:enums.envelope.shape.TCB; tempKey.tension = obj.tension?obj.tension:0; tempKey.continuity = obj.continuity?obj.continuity:0; tempKey.bias = obj.bias?obj.bias:0; tempKey.param = obj.param?obj.param:[0,0,0,0]; } else { tempKey = this.insertKey(time); tempKey.value = value; } return tempKey; }; Envelope.prototype.insertKey = function(time) { var tempKey = new EnvelopeKey(); tempKey.time = time; if (!this.nKeys) { this.keys = tempKey; this.firstKey = tempKey; this.lastKey = tempKey; this.nKeys++; return tempKey; } var k1 = this.keys; while (k1) { // update first/last key if (this.firstKey.time > time) { this.firstKey = tempKey; } else if (this.lastKey.time < time) { this.lastKey = tempKey; } if (k1.time > tempKey.time) { tempKey.prev = k1.prev; if (tempKey.prev) { tempKey.prev.next = tempKey; } tempKey.next = k1; tempKey.next.prev = tempKey; this.nKeys++; return tempKey; } else if (!k1.next) { tempKey.prev = k1; k1.next = tempKey; this.nKeys++; return tempKey; } k1 = k1.next; } return null; // you should not be here, time and space has imploded }; Envelope.prototype.evaluate = function(time) { var key0, key1, skey, ekey; var t, h1, h2, h3, h4, inval, out, offset = 0.0; var noff; /* if there's no key, the value is 0 */ if (this.nKeys === 0) { return 0.0; } /* if there's only one key, the value is constant */ if (this.nKeys === 1) { return (this.keys).value; } /* find the first and last keys */ skey = this.firstKey; ekey = this.lastKey; var tmp, behavior; /* use pre-behavior if time is before first key time */ if (time < skey.time) { behavior = this.in_behavior; if (behavior === enums.envelope.behavior.RESET) { return 0.0; } else if (behavior === enums.envelope.behavior.CONSTANT) { return skey.value; } else if (behavior === enums.envelope.behavior.REPEAT) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; } else if (behavior === enums.envelope.behavior.OCILLATE) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; if (noff % 2) { time = ekey.time - skey.time - time; } } else if (behavior === enums.envelope.behavior.OFFSET) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; offset = noff * (ekey.value - skey.value); } else if (behavior === enums.envelope.behavior.LINEAR) { out = cubicvr_env_outgoing(skey, skey.next) / (skey.next.time - skey.time); return out * (time - skey.time) + skey.value; } /* switch (this.in_behavior) { case enums.envelope.behavior.RESET: return 0.0; case enums.envelope.behavior.CONSTANT: return skey.value; case enums.envelope.behavior.REPEAT: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; break; case enums.envelope.behavior.OSCILLATE: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; if (noff % 2) { time = ekey.time - skey.time - time; } break; case enums.envelope.behavior.OFFSET: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; offset = noff * (ekey.value - skey.value); break; case enums.envelope.behavior.LINEAR: out = cubicvr_env_outgoing(skey, skey.next) / (skey.next.time - skey.time); return out * (time - skey.time) + skey.value; } */ } /* use post-behavior if time is after last key time */ else if (time > ekey.time) { behavior = this.out_behavior; if (behavior === enums.envelope.behavior.RESET) { return 0.0; } else if (behavior === enums.envelope.behavior.CONSTANT) { return ekey.value; } else if (behavior === enums.envelope.behavior.REPEAT) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; } else if (behavior === enums.envelope.behavior.OCILLATE) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; if (noff % 2) { time = ekey.time - skey.time - time; } } else if (behavior === enums.envelope.behavior.OFFSET) { tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; offset = noff * (ekey.value - skey.value); } else if (behavior === enums.envelope.behavior.LINEAR) { inval = cubicvr_env_incoming(ekey.prev, ekey) / (ekey.time - ekey.prev.time); return inval * (time - ekey.time) + ekey.value; } /* switch (this.out_behavior) { case enums.envelope.behavior.RESET: return 0.0; case enums.envelope.behavior.CONSTANT: return ekey.value; case enums.envelope.behavior.REPEAT: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; break; case enums.envelope.behavior.OSCILLATE: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; if (noff % 2) { time = ekey.time - skey.time - time; } break; case enums.envelope.behavior.OFFSET: tmp = cubicvr_env_range(time, skey.time, ekey.time); time = tmp[0]; noff = tmp[1]; offset = noff * (ekey.value - skey.value); break; case enums.envelope.behavior.LINEAR: inval = cubicvr_env_incoming(ekey.prev, ekey) / (ekey.time - ekey.prev.time); return inval * (time - ekey.time) + ekey.value; } */ } // get the endpoints of the interval being evaluated key0 = this.keys; while (time > key0.next.time) { key0 = key0.next; } key1 = key0.next; // check for singularities first if (time === key0.time) { return key0.value + offset; } else if (time === key1.time) { return key1.value + offset; } // get interval length, time in [0, 1] t = (time - key0.time) / (key1.time - key0.time); // interpolate /* switch (key1.shape) { case enums.envelope.shape.TCB: case enums.envelope.shape.BEZI: case enums.envelope.shape.HERM: out = cubicvr_env_outgoing(key0, key1); inval = cubicvr_env_incoming(key0, key1); var h = cubicvr_env_hermite(t); return h[0] * key0.value + h[1] * key1.value + h[2] * out + h[3] * inval + offset; case enums.envelope.shape.BEZ2: return cubicvr_env_bez2_time(key0, key1, time) + offset; case enums.envelope.shape.LINE: return key0.value + t * (key1.value - key0.value) + offset; case enums.envelope.shape.STEP: return key0.value + offset; default: return offset; } */ var keyShape = key1.shape; if (keyShape === enums.envelope.shape.TCB || keyShape === enums.envelope.shape.BEZI || keyShape === enums.envelope.shape.HERM) { out = cubicvr_env_outgoing(key0, key1); inval = cubicvr_env_incoming(key0, key1); var h = cubicvr_env_hermite(t); return h[0] * key0.value + h[1] * key1.value + h[2] * out + h[3] * inval + offset; } else if (keyShape === enums.envelope.shape.BEZ2) { return cubicvr_env_bez2(key0, key1, time) + offset; } else if (keyShape === enums.envelope.shape.LINE) { return key0.value + t * (key1.value - key0.value) + offset; } else if (keyShape === enums.envelope.shape.STEP) { return key0.value + offset; } else { return offset; } }; function Motion(env_init, key_init) { this.env_init = env_init; this.key_init = key_init; this.controllers = []; this.yzflip = false; // this.rscale = 1; } Motion.prototype.envelope = function(controllerId, motionId) { if (this.controllers[controllerId] === undef) { this.controllers[controllerId] = []; } if (this.controllers[controllerId][motionId] === undef) { this.controllers[controllerId][motionId] = new Envelope(this.env_init); } return this.controllers[controllerId][motionId]; }; Motion.prototype.evaluate = function(index) { var retArr = []; for (var i in this.controllers) { if (this.controllers.hasOwnProperty(i)) { retArr[i] = []; for (var j in this.controllers[i]) { if (this.controllers[i].hasOwnProperty(j)) { retArr[i][j] = this.controllers[i][j].evaluate(index); } } } } return retArr; }; Motion.prototype.apply = function(index, target) { for (var i in this.controllers) { if (this.controllers.hasOwnProperty(i)) { var ic = parseInt(i, 10); /* Special case quaternion fix for ZY->YZ rotation envelopes */ if (this.yzflip && ic === enums.motion.ROT) // assume channel 0,1,2 { if (!this.q) { this.q = new Quaternion(); } var q = this.q; var x = this.controllers[i][0].evaluate(index); var y = this.controllers[i][1].evaluate(index); var z = this.controllers[i][2].evaluate(index); //q.fromEuler(x*this.rscale, z*this.rscale, -y*this.rscale); q.fromEuler(x, z, -y); var qr = q.toEuler(); target.control(ic, 0, qr[0]); target.control(ic, 1, qr[1]); target.control(ic, 2, qr[2]); } else { for (var j in this.controllers[i]) { if (this.controllers[i].hasOwnProperty(j)) { target.control(ic, parseInt(j, 10), this.controllers[i][j].evaluate(index)); } } } } } }; Motion.prototype.setKey = function(controllerId, motionId, index, value, key_init) { var ev = this.envelope(controllerId, motionId); return ev.addKey(index, value, key_init?key_init:this.key_init); }; Motion.prototype.setArray = function(controllerId, index, value, key_init) { var tmpKeys = []; for (var i in value) { if (value.hasOwnProperty(i)) { var ev = this.envelope(controllerId, i); tmpKeys[i] = ev.addKey(index, value[i], key_init?key_init:this.key_init); } } return tmpKeys; }; Motion.prototype.setBehavior = function(controllerId, motionId, behavior_in, behavior_out) { var ev = this.envelope(controllerId, motionId); ev.setBehavior(behavior_in, behavior_out); }; Motion.prototype.setBehaviorArray = function(controllerId, behavior_in, behavior_out) { for (var motionId in this.controllers[controllerId]) { if (this.controllers[controllerId].hasOwnProperty(motionId)) { var ev = this.envelope(controllerId, motionId); ev.setBehavior(behavior_in, behavior_out); } } }; function cubicvr_nodeToMotion(node, controllerId, motion) { var c = []; c[0] = node.getElementsByTagName("x"); c[1] = node.getElementsByTagName("y"); c[2] = node.getElementsByTagName("z"); c[3] = node.getElementsByTagName("fov"); var etime, evalue, ein, eout, etcb; for (var k in c) { if (c.hasOwnProperty(k)) { if (c[k] !== undef) { if (c[k].length) { etime = c[k][0].getElementsByTagName("time"); evalue = c[k][0].getElementsByTagName("value"); ein = c[k][0].getElementsByTagName("in"); eout = c[k][0].getElementsByTagName("out"); etcb = c[k][0].getElementsByTagName("tcb"); var time = null, value = null, tcb = null; var intype = null, outtype = null; if (ein.length) { intype = util.collectTextNode(ein[0]); } if (eout.length) { outtype = util.collectTextNode(eout[0]); } if (etime.length) { time = util.floatDelimArray(util.collectTextNode(etime[0]), " "); } if (evalue.length) { value = util.floatDelimArray(util.collectTextNode(evalue[0]), " "); } if (etcb.length) { tcb = util.floatDelimArray(util.collectTextNode(etcb[0]), " "); } if (time !== null && value !== null) { for (var i = 0, iMax = time.length; i < iMax; i++) { var mkey = motion.setKey(controllerId, k, time[i], value[i]); if (tcb) { mkey.tension = tcb[i * 3]; mkey.continuity = tcb[i * 3 + 1]; mkey.bias = tcb[i * 3 + 2]; } } } var in_beh = enums.envelope.behavior.CONSTANT; var out_beh = enums.envelope.behavior.CONSTANT; if (intype) { switch (intype) { case "reset": in_beh = enums.envelope.behavior.RESET; break; case "constant": in_beh = enums.envelope.behavior.CONSTANT; break; case "repeat": in_beh = enums.envelope.behavior.REPEAT; break; case "oscillate": in_beh = enums.envelope.behavior.OSCILLATE; break; case "offset": in_beh = enums.envelope.behavior.OFFSET; break; case "linear": in_beh = enums.envelope.behavior.LINEAR; break; } } if (outtype) { switch (outtype) { case "reset": out_beh = enums.envelope.behavior.RESET; break; case "constant": out_beh = enums.envelope.behavior.CONSTANT; break; case "repeat": out_beh = enums.envelope.behavior.REPEAT; break; case "oscillate": out_beh = enums.envelope.behavior.OSCILLATE; break; case "offset": out_beh = enums.envelope.behavior.OFFSET; break; case "linear": out_beh = enums.envelope.behavior.LINEAR; break; } } motion.setBehavior(controllerId, k, in_beh, out_beh); } } } } } function cubicvr_isMotion(node) { if (node === null) { return false; } return (node.getElementsByTagName("x").length || node.getElementsByTagName("y").length || node.getElementsByTagName("z").length || node.getElementsByTagName("fov").length); } /*********************************************** * Plane ***********************************************/ function Plane() { this.a = 0; this.b = 0; this.c = 0; this.d = 0; } //Plane::Constructor Plane.prototype.classify_point = function(pt) { var dist = (this.a * pt[0]) + (this.b * pt[1]) + (this.c * pt[2]) + (this.d); if (dist < 0) { return -1; } if (dist > 0) { return 1; } return 0; }; //Plane::classify_point Plane.prototype.normalize = function() { var mag = Math.sqrt(this.a * this.a + this.b * this.b + this.c * this.c); this.a = this.a / mag; this.b = this.b / mag; this.c = this.c / mag; this.d = this.d / mag; }; //Plane::normalize Plane.prototype.toString = function() { return "[Plane " + this.a + ", " + this.b + ", " + this.c + ", " + this.d + "]"; }; //Plane::toString /*********************************************** * Sphere ***********************************************/ function Sphere(position, radius) { this.position = position; if (this.position === undef) { this.position = [0, 0, 0]; } this.radius = radius; } //Sphere::Constructor Sphere.prototype.intersects = function(other_sphere) { var diff = vec3.subtract(this.position, other_sphere.position); var mag = Math.sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]); var sum_radii = this.radius + other_sphere.radius; if (mag * mag < sum_radii * sum_radii) { return true; } return false; }; //Sphere::intersects function OctreeWorkerProxy(size, depth) { var that = this; this.size = size; this.depth = depth; this.worker = new CubicVR_Worker({ message: function(e) { console.log('Octree Worker Message:', e); }, error: function(e) { console.log('Octree Worker Error:', e); }, type: 'octree'}); this.worker.start(); this.init = function(scene) { that.scene = scene; that.worker.init({ size: that.size, max_depth: that.depth, camera: scene.camera }); }; //init this.insert = function(node) { that.worker.send({message:'insert', node:node}); }; //insert this.draw_on_map = function() { return; }; //draw_on_map this.reset_node_visibility = function() { return; }; //reset_node_visibility this.get_frustum_hits = function() { }; //get_frustum_hits } //OctreeWorkerProxy function Octree(size, max_depth, root, position, child_index) { this._children = []; this._dirty = false; this._children[0] = null; this._children[1] = null; this._children[2] = null; this._children[3] = null; this._children[4] = null; this._children[5] = null; this._children[6] = null; this._children[7] = null; if (child_index === undef) { this._child_index = -1; } else { this._child_index = child_index; } if (size === undef) { this._size = 0; } else { this._size = size; } if (max_depth === undef) { this._max_depth = 0; } else { this._max_depth = max_depth; } if (root === undef) { this._root = null; } else { this._root = root; } if (position === undef) { this._position = [0, 0, 0]; } else { this._position = position; } this._nodes = []; //this._static_nodes = []; this._lights = []; this._static_lights = []; this._sphere = new Sphere(this._position, Math.sqrt(3 * (this._size / 2 * this._size / 2))); this._bbox = [[0,0,0],[0,0,0]]; AABB_reset(this._bbox, this._position); var s = this._size/2; AABB_engulf(this._bbox, [this._position[0] + s, this._position[1] + s, this._position[2] + s]); AABB_engulf(this._bbox, [this._position[0] - s, this._position[1] - s, this._position[2] - s]); this._debug_visible = false; } //Octree::Constructor Array_remove = function(arr, from, to) { var rest = arr.slice((to || from) + 1 || arr.length); arr.length = from < 0 ? arr.length + from : from; return arr.push.apply(arr, rest); }; Octree.prototype.destroy = function() { for (var i=0, li = this._static_lights.length; i= 0; --i) { if (node === this._nodes[i]) { Array_remove(this._nodes, i); this.dirty_lineage(); dont_check_lights = true; break; } //if } //for if (!dont_check_lights) { for (i = len - 1, len = this._lights.length; i >= 0; --i) { if (node === this._lights[i]) { Array_remove(this._lights, i); this.dirty_lineage(); break; } //if } //for } //if }; //Octree::remove Octree.prototype.dirty_lineage = function() { this._dirty = true; if (this._root !== null) { this._root.dirty_lineage(); } } //Octree::dirty_lineage Octree.prototype.cleanup = function() { var num_children = this._children.length; var num_keep_children = 0; for (var i = 0; i < num_children; ++i) { var child = this._children[i]; if (child !== null) { var keep = true; if (child._dirty === true) { keep = child.cleanup(); } //if if (!keep) { this._children[i] = null; } else { ++num_keep_children; } } //if } //for if ((this._nodes.length === 0 && this._static_lights.length === 0 && this._lights.length === 0) && (num_keep_children === 0 || num_children === 0)) { return false; } return true; }; //Octree::cleanup Octree.prototype.insert_light = function(light) { this.insert(light, true); }; //insert_light Octree.prototype.propagate_static_light = function(light) { var i,l; for (i = 0, l = this._nodes.length; i < l; ++i) { if (this._nodes[i].static_lights.indexOf(light) === -1) { this._nodes[i].static_lights.push(light); } //if } //for for (i = 0; i < 8; ++i) { if (this._children[i] !== null) { this._children[i].propagate_static_light(light); } //if } //for }; //propagate_static_light Octree.prototype.collect_static_lights = function(node) { for (var i=0, li = this._static_lights.length; i p[0] && min[1] < p[1] && min[2] < p[2]; b_nw = min[0] < p[0] && max[1] > p[1] && min[2] < p[2]; b_ne = max[0] > p[0] && max[1] > p[1] && min[2] < p[2]; t_sw = min[0] < p[0] && min[1] < p[1] && max[2] > p[2]; t_se = max[0] > p[0] && min[1] < p[1] && max[2] > p[2]; b_sw = min[0] < p[0] && max[1] > p[1] && max[2] > p[2]; b_se = max[0] > p[0] && max[1] > p[1] && max[2] > p[2]; //Is it in every sector? if (t_nw && t_ne && b_nw && b_ne && t_sw && t_se && b_sw && b_se) { $insert(this, node, is_light, this); if (is_light) { if (node.method == enums.light.method.STATIC) { this.propagate_static_light(node); } //if } else { this.collect_static_lights(node); } //if } else { //Add static lights in this octree for (var i=0, ii=this._static_lights.length; i 1 || node.octree_common_root === null) { node.octree_common_root = this; } //if } //if }; //Octree::insert Octree.prototype.draw_on_map = function(map_canvas, map_context, target) { var mhw = map_canvas.width/2; var mhh = map_canvas.height/2; var x, y, w, h; var i, len; if (target === undef || target === "map") { map_context.save(); if (this._debug_visible !== false) { map_context.fillStyle = "rgba(0,0,0,0)"; map_context.strokeStyle = "#FF0000"; } else { map_context.fillStyle = "rgba(0,0,0,0)"; map_context.strokeStyle = "rgba(0,0,0,0)"; } //if map_context.beginPath(); var offset = this._size / 2; x = this._position[0]; y = this._position[2]; map_context.moveTo(mhw + x - offset, mhw + y - offset); map_context.lineTo(mhw + x - offset, mhw + y + offset); map_context.lineTo(mhw + x + offset, mhw + y + offset); map_context.lineTo(mhw + x + offset, mhw + y - offset); map_context.stroke(); map_context.fill(); map_context.restore(); } if (target === undef || target === "objects") { map_context.save(); for (i = 0, len = this._nodes.length; i < len; ++i) { var n = this._nodes[i]; map_context.fillStyle = "#5500FF"; if (n.visible === true && n.culled === false) { map_context.strokeStyle = "#FFFFFF"; } else { map_context.strokeStyle = "#000000"; } //if map_context.beginPath(); x = n.aabb[0][0]; y = n.aabb[0][2]; w = n.aabb[1][0] - x; h = n.aabb[1][2] - y; map_context.rect(mhw + x, mhh + y, w, h); map_context.stroke(); } //for map_context.restore(); } if (target === undef || target === "lights") { for (i = 0, len = this._lights.length; i < len; ++i) { var l = this._lights[i]; if (l.culled === false && l.visible === true) { map_context.fillStyle = "rgba(255, 255, 255, 0.1)"; } else { map_context.fillStyle = "rgba(255, 255, 255, 0.0)"; } map_context.strokeStyle = "#FFFF00"; map_context.beginPath(); var d = l.distance; x = l.position[0]; y = l.position[2]; map_context.arc(mhw + x, mhh + y, d, 0, Math.PI * 2, true); map_context.closePath(); map_context.stroke(); map_context.fill(); map_context.beginPath(); x = l.aabb[0][0]; y = l.aabb[0][2]; w = l.aabb[1][0] - x; h = l.aabb[1][2] - y; map_context.rect(mhw + x, mhh + y, w, h); map_context.closePath(); map_context.stroke(); } //for for (i = 0, len = this._static_lights.length; i < len; ++i) { var l = this._static_lights[i]; if (l.culled === false && l.visible === true) { map_context.fillStyle = "rgba(255, 255, 255, 0.01)"; } else { map_context.fillStyle = "rgba(255, 255, 255, 0.0)"; } map_context.strokeStyle = "#FF66BB"; map_context.beginPath(); var d = l.distance; x = l.position[0]; y = l.position[2]; map_context.arc(mhw + x, mhh + y, d, 0, Math.PI * 2, true); map_context.closePath(); map_context.stroke(); map_context.fill(); map_context.beginPath(); x = l.aabb[0][0]; y = l.aabb[0][2]; w = l.aabb[1][0] - x; h = l.aabb[1][2] - y; map_context.rect(mhw + x, mhh + y, w, h); map_context.closePath(); map_context.stroke(); } //for } //if function $draw_box(x1, y1, x2, y2, fill) { var x = x1 < x2 ? x1 : x2; var y = y1 < y2 ? y1 : y2; var w = x1 < x2 ? x2-x1 : x1-x2; var h = y1 < y2 ? y2-y1 : y1-y2; map_context.save(); if (fill !== undefined) { map_context.fillStyle = fill; map_context.fillRect(mhw+x,mhh+y,w,h); } //if map_context.strokeRect(mhw+x,mhh+y,w,h); map_context.restore(); } //$draw_box function $draw_oct(oct, fill) { var x1 = oct._bbox[0][0]; var y1 = oct._bbox[0][2]; var x2 = oct._bbox[1][0]; var y2 = oct._bbox[1][2]; $draw_box(x1, y1, x2, y2, fill); } //$draw_oct if (target != "lights" && target != "objects" && target != "map") { map_context.save(); var nodes = this._nodes; for (var i=0,l=nodes.length;i= this._position[0] - this._size / 2 && position[1] >= this._position[1] - this._size / 2 && position[2] >= this._position[2] - this._size / 2; }; //Octree::contains_point Octree.prototype.get_frustum_hits = function(camera, test_children) { var hits = { objects: [], lights: [] }; if (test_children === undef || test_children === true) { if (! (this.contains_point(camera.position))) { if (camera.frustum.sphere.intersects(this._sphere) === false) { return hits; } //if(_sphere.intersects(c.get_frustum().get_cone()) === false) return; var contains_sphere = camera.frustum.contains_sphere(this._sphere); if (contains_sphere === -1) { this._debug_visible = false; return hits; } else if (contains_sphere === 1) { this._debug_visible = 2; test_children = false; } else if (contains_sphere === 0) { this._debug_visible = true; var contains_box = camera.frustum.contains_box(this._bbox); if (contains_box === -1) { this._debug_visible = false; return hits; } else if (contains_box === 1) { this._debug_visible = 3; test_children = false; } //if } //if } //if } //if var i, max_i; for (i = 0, max_i = this._nodes.length; i < max_i; ++i) { var n = this._nodes[i]; hits.objects.push(n); n.dynamic_lights = [].concat(this._lights); n.was_culled = n.culled; n.culled = false; n.drawn_this_frame = false; } //for objects this._debug_visible = this._lights.length > 0 ? 4 : this._debug_visible; for (i = 0, max_i = this._lights.length; i < max_i; ++i) { var l = this._lights[i]; if (l.visible === true) { hits.lights.push(l); l.was_culled = l.culled; l.culled = false; } //if } //for dynamic lights for (i = 0, max_i = this._static_lights.length; i < max_i; ++i) { var l = this._static_lights[i]; if (l.visible === true) { l.culled = false; } //if } //for static lights for (i = 0; i < 8; ++i) { if (this._children[i] !== null) { var child_hits = this._children[i].get_frustum_hits(camera, test_children); var o, max_o; for (o = 0, max_o = child_hits.objects.length; o < max_o; ++o) { hits.objects.push(child_hits.objects[o]); var obj_lights = child_hits.objects[o].dynamic_lights; for (var j=0, lj=this._lights.length; j this.bounds[0][0] && pt[1] > this.bounds[0][1] && pt[2] > this.bounds[0][2] && pt[0] < this.bounds[1][0] && pt[1] < this.bounds[1][1] && pt[2] < this.bounds[1][2])) { return false; } for (var i = 0, iMax = this.avoid_sphere.length; i < iMax; i++) { var l = vec3.length(pt, this.avoid_sphere[i][0]); if (l < this.avoid_sphere[i][1]) { return false; } } return true; }; AutoCamera.prototype.findNextNode = function(aNode, bNode) { var d = [this.bounds[1][0] - this.bounds[0][0], this.bounds[1][1] - this.bounds[0][1], this.bounds[1][2] - this.bounds[0][2]]; var nextNodePos = [0, 0, 0]; var randVector = [0, 0, 0]; var l = 0.0; var loopkill = 0; var valid = false; do { randVector[0] = Math.random() - 0.5; randVector[1] = Math.random() - 0.5; randVector[2] = Math.random() - 0.5; randVector = vec3.normalize(randVector); var r = Math.random(); l = (r * (this.max_distance - this.min_distance)) + this.min_distance; nextNodePos = vec3.add(bNode.position, vec3.multiply(randVector, l)); valid = this.inBounds(nextNodePos); loopkill++; if (loopkill > 30) { nextNodePos = bNode.position; break; } } while (!valid); return nextNodePos; }; AutoCamera.prototype.run = function(timer) { this.current_time = timer; if (this.path_time === 0.0) { this.path_time = this.current_time; this.camPath.setKey(enums.motion.POS, enums.motion.X, this.path_time, this.start_position[0]); this.camPath.setKey(enums.motion.POS, enums.motion.Y, this.path_time, this.start_position[1]); this.camPath.setKey(enums.motion.POS, enums.motion.Z, this.path_time, this.start_position[2]); } while (this.path_time < this.current_time + this.buffer_time) { this.path_time += this.segment_time; var tmpNodeA = new AutoCameraNode(); var tmpNodeB = new AutoCameraNode(); if (this.path_length) { this.camPath.apply(this.path_time - (this.segment_time * 2.0), tmpNodeA); } this.camPath.apply(this.path_time - this.segment_time, tmpNodeB); var nextPos = this.findNextNode(tmpNodeA, tmpNodeB); this.camPath.setKey(enums.motion.POS, enums.motion.X, this.path_time, nextPos[0]); this.camPath.setKey(enums.motion.POS, enums.motion.Y, this.path_time, nextPos[1]); this.camPath.setKey(enums.motion.POS, enums.motion.Z, this.path_time, nextPos[2]); this.path_length++; } var tmpNodeC = new AutoCameraNode(); this.camPath.apply(timer, tmpNodeC); return tmpNodeC.position; }; AutoCamera.prototype.addSafeBound = function(min, max) { this.safe_bb.push([min, max]); }; AutoCamera.prototype.addAvoidSphere = function(center, radius) { this.avoid_sphere.push([center, radius]); }; function Scene(width, height, fov, nearclip, farclip, octree) { this.frames = 0; this.sceneObjects = []; this.sceneObjectsByName = []; this.sceneObjectsById = []; this.lights = []; this.global_lights = []; this.dynamic_lights = []; this.pickables = []; this.octree = octree; this.skybox = null; this.camera = new Camera(width, height, fov, nearclip, farclip); this._workers = null; this.stats = []; this.collect_stats = false; } Scene.prototype.attachOctree = function(octree) { this.octree = octree; if (octree.init) { octree.init(this); } //if // rebind any active lights var tmpLights = this.lights; this.lights = []; for (var l = 0, lMax = tmpLights.length; l < lMax; l++) { this.bindLight(tmpLights[l]); } //for var objs = this.sceneObjects; if (this.octree !== undef) { for (var i=0, l=objs.length; i= bb1[0] && testPt[0] <= bb2[0]) ? 1 : 0) + ((testPt[1] >= bb1[1] && testPt[1] <= bb2[1]) ? 1 : 0) + ((testPt[2] >= bb1[2] && testPt[2] <= bb2[2]) ? 1 : 0); if (matches >= axisMatch) { selList.push({dist:testDist, obj:obj}); } } } if (selList.length) { selList.sort(function(a,b) { if (a.dist==b.dist) return 0; return (a.dist s) s *= 2; // // return s; }; RenderBuffer.prototype.use = function() { var gl = GLCore.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo); // if (this.depth !== null) { gl.bindRenderbuffer(gl.RENDERBUFFER, this.depth); } // gl.viewport(0, 0, this.width, this.height); }; function PostProcessFX(width, height) { this.bloom = true; this.renderBuffer = new RenderBuffer(width, height, true); this.blurBuffer = new RenderBuffer(width, height, false); this.bloomBuffer = new RenderBuffer(parseInt(width / 6, 10), parseInt(height / 6, 10), false); this.copyShader = new Shader("attribute vec3 aVertex;\n" + "attribute vec2 aTex;\n" + "varying vec2 vTex;\n" + "void main(void)\n" + "{\n" + "vTex = aTex;\n" + "vec4 vPos = vec4(aVertex.xyz,1.0);\n" + "gl_Position = vPos;\n" + "}\n", "#ifdef GL_ES\nprecision highp float;\n#endif\n" + "uniform sampler2D srcTex;\n" + "varying vec2 vTex;\n" + "void main(void)\n" + "{\n" + "gl_FragColor = texture2D(srcTex, vTex);\n" + "}\n"); this.copyShader.use(); this.copyShader.addUVArray("aTex"); this.copyShader.addVertexArray("aVertex"); this.copyShader.addInt("srcTex", 0); this.fsQuad = this.makeFSQuad(width, height); this.bloomShader = new Shader("attribute vec3 aVertex;\n" + "attribute vec2 aTex;\n" + "varying vec2 vTex;\n" + "void main(void)\n" + "{\n" + "vTex = aTex;\n" + "vec4 vPos = vec4(aVertex.xyz,1.0);\n" + "gl_Position = vPos;\n" + "}\n", "#ifdef GL_ES\nprecision highp float;\n#endif\n" + "uniform sampler2D srcTex;\n" + "uniform vec3 texel_ofs;\n" + "varying vec2 vTex;\n" + "vec3 rangeValHDR(vec3 src)\n" + "{\n" + "return (src.r>0.90||src.g>0.90||src.b>0.90)?(src):vec3(0.0,0.0,0.0);\n" + "}\n" + "vec4 hdrSample(float rad)\n" + "{\n" + "vec3 accum;\n" + "float radb = rad*0.707106781;\n" + "accum = rangeValHDR(texture2D(srcTex, vec2(vTex.s+texel_ofs.x*rad, vTex.t)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s, vTex.t+texel_ofs.y*rad)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s-texel_ofs.x*rad, vTex.t)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s, vTex.t-texel_ofs.y*rad)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s+texel_ofs.x*radb, vTex.t+texel_ofs.y*radb)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s-texel_ofs.x*radb, vTex.t-texel_ofs.y*radb)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s+texel_ofs.x*radb, vTex.t-texel_ofs.y*radb)).rgb);\n" + "accum += rangeValHDR(texture2D(srcTex, vec2(vTex.s-texel_ofs.x*radb, vTex.t+texel_ofs.y*radb)).rgb);\n" + "accum /= 8.0;\n" + "return vec4(accum,1.0);\n" + "}\n" + "void main(void)\n" + "{\n" + "vec4 color;\n" + "color = hdrSample(2.0);\n" + "color += hdrSample(8.0);\n" + "color += hdrSample(12.0);\n" + "gl_FragColor = color/2.0;\n" + "}\n"); this.bloomShader.use(); this.bloomShader.addUVArray("aTex"); this.bloomShader.addVertexArray("aVertex"); this.bloomShader.addInt("srcTex", 0); this.bloomShader.addVector("texel_ofs"); this.bloomShader.setVector("texel_ofs", [1.0 / this.renderBuffer.sizeParam(width), 1.0 / this.renderBuffer.sizeParam(height), 0]); this.fsQuadBloom = this.makeFSQuad(this.bloomBuffer.width, this.bloomBuffer.height); this.blurShader = new Shader("attribute vec3 aVertex;\n" + "attribute vec2 aTex;\n" + "varying vec2 vTex;\n" + "void main(void)\n" + "{\n" + "vTex = aTex;\n" + "vec4 vPos = vec4(aVertex.xyz,1.0);\n" + "gl_Position = vPos;\n" + "}\n", "#ifdef GL_ES\nprecision highp float;\n#endif\n" + "uniform sampler2D srcTex;\n" + "varying vec2 vTex;\n" + "uniform float opacity;\n" + "void main(void)\n" + "{\n" + "gl_FragColor = vec4(texture2D(srcTex, vTex).rgb, opacity);\n" + "}\n"); this.blurShader.use(); this.blurShader.addUVArray("aTex"); this.blurShader.addVertexArray("aVertex"); this.blurShader.addInt("srcTex", 0); this.blurShader.addFloat("opacity"); this.blurOpacity = 0.1; var gl = GLCore.gl; this.blurBuffer.use(); gl.clear(gl.COLOR_BUFFER_BIT); this.end(); } PostProcessFX.prototype.resize = function(width, height) { this.renderBuffer.destroyBuffer(); this.blurBuffer.destroyBuffer(); this.bloomBuffer.destroyBuffer(); this.renderBuffer.createBuffer(width, height, true); this.blurBuffer.createBuffer(width, height, false); this.bloomBuffer.createBuffer(parseInt(width / 6, 10), parseInt(height / 6, 10), false); this.bloomShader.use(); this.bloomShader.setVector("texel_ofs", [1.0 / this.renderBuffer.sizeParam(width), 1.0 / this.renderBuffer.sizeParam(height), 0]); this.destroyFSQuad(this.fsQuad); this.fsQuad = this.makeFSQuad(width, height); this.destroyFSQuad(this.fsQuadBloom); this.fsQuadBloom = this.makeFSQuad(this.bloomBuffer.width, this.bloomBuffer.height); }; PostProcessFX.prototype.begin = function() { this.renderBuffer.use(); }; PostProcessFX.prototype.end = function() { var gl = GLCore.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, null); // if (this.depth !== null) { gl.bindRenderbuffer(gl.RENDERBUFFER, null); } }; PostProcessFX.prototype.makeFSQuad = function(width, height) { var gl = GLCore.gl; var fsQuad = []; // intentional empty object // var w = this.renderBuffer.sizeParam(width); // var h = this.renderBuffer.sizeParam(height); // var uscale = (width / w); // var vscale = (height / h); var uscale, vscale; uscale=vscale=1; // fsQuad.addPoint([[-1,-1,0],[1, -1, 0],[1, 1, 0],[-1, 1, 0]]); // var faceNum = fsQuad.addFace([0,1,2,3]); // fsQuad.faces[faceNum].setUV([[0, 0],[uscale, 0],[uscale, vscale],[0, vscale]]); // fsQuad.triangulateQuads(); // fsQuad.calcNormals(); // fsQuad.compile(); fsQuad.vbo_points = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0]); fsQuad.vbo_uvs = new Float32Array([0, 0, uscale, 0, uscale, vscale, 0, vscale, 0, 0, uscale, vscale]); fsQuad.gl_points = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, fsQuad.gl_points); gl.bufferData(gl.ARRAY_BUFFER, fsQuad.vbo_points, gl.STATIC_DRAW); fsQuad.gl_uvs = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, fsQuad.gl_uvs); gl.bufferData(gl.ARRAY_BUFFER, fsQuad.vbo_uvs, gl.STATIC_DRAW); return fsQuad; }; PostProcessFX.prototype.destroyFSQuad = function(fsQuad) { var gl = GLCore.gl; gl.deleteBuffer(fsQuad.gl_points); gl.deleteBuffer(fsQuad.gl_uvs); }; PostProcessFX.prototype.renderFSQuad = function(shader, fsq) { var gl = GLCore.gl; shader.use(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindBuffer(gl.ARRAY_BUFFER, fsq.gl_points); gl.vertexAttribPointer(shader.aVertex, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribPointer(shader.aVertex); gl.bindBuffer(gl.ARRAY_BUFFER, fsq.gl_uvs); gl.vertexAttribPointer(shader.aTex, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribPointer(shader.aTex); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.drawArrays(gl.TRIANGLES, 0, 6); }; PostProcessFX.prototype.render = function() { var gl = GLCore.gl; gl.disable(gl.DEPTH_TEST); this.renderBuffer.texture.use(gl.TEXTURE0); this.copyShader.use(); this.copyShader.setInt("srcTex", 0); this.renderFSQuad(this.copyShader, this.fsQuad); if (this.blur) { this.renderBuffer.texture.use(gl.TEXTURE0); this.blurShader.use(); this.blurShader.setInt("srcTex", 0); this.blurShader.setFloat("opacity", this.blurOpacity); this.blurBuffer.use(); gl.enable(gl.BLEND); gl.depthMask(0); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); this.renderFSQuad(this.blurShader, this.fsQuad); gl.disable(gl.BLEND); gl.depthMask(1); gl.blendFunc(gl.ONE, gl.ONE); this.end(); this.blurBuffer.texture.use(gl.TEXTURE0); this.blurShader.setFloat("opacity", 0.5); gl.enable(gl.BLEND); gl.depthMask(0); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); this.renderFSQuad(this.blurShader, this.fsQuad); gl.disable(gl.BLEND); gl.depthMask(1); gl.blendFunc(gl.ONE, gl.ONE); } if (this.bloom) { this.renderBuffer.texture.use(gl.TEXTURE0); gl.viewport(0, 0, this.bloomBuffer.width, this.bloomBuffer.height); this.bloomShader.use(); this.bloomShader.setInt("srcTex", 0); this.bloomBuffer.use(); this.renderFSQuad(this.bloomShader, this.fsQuad); this.end(); this.bloomBuffer.texture.use(gl.TEXTURE0); this.copyShader.use(); this.copyShader.setInt("srcTex", 0); gl.viewport(0, 0, this.renderBuffer.width, this.renderBuffer.height); gl.enable(gl.BLEND); gl.depthMask(0); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); this.renderFSQuad(this.copyShader, this.fsQuadBloom); gl.disable(gl.BLEND); gl.depthMask(1); gl.blendFunc(gl.ONE, gl.ONE); } gl.enable(gl.DEPTH_TEST); }; /* PostProcessShader: shaderInfo { enabled: enabled (default true) shader_vertex: id or url for vertex shader shader_fragment: id or url for fragment shader outputMode: method of output for this shader init: function to perform to initialize shader onresize: function to perform on resize; params ( shader, width, height ) onupdate: function to perform on update; params ( shader ) outputDivisor: use custom output buffer size, divisor of (outputDivisor) eg. 1 (default) = 1024x768, 2 = 512x384, 3 = 256x192 } */ var postProcessDivisorBuffers = []; var postProcessDivisorQuads = []; function PostProcessShader(shaderInfo) { if (shaderInfo.shader_vertex === undef) { return null; } if (shaderInfo.shader_fragment === undef) { return null; } this.outputMode = (shaderInfo.outputMode === undef) ? enums.post.output.REPLACE : shaderInfo.outputMode; this.onresize = (shaderInfo.onresize === undef) ? null : shaderInfo.onresize; this.onupdate = (shaderInfo.onupdate === undef) ? null : shaderInfo.onupdate; this.init = (shaderInfo.init === undef) ? null : shaderInfo.init; this.enabled = (shaderInfo.enabled === undef) ? true : shaderInfo.enabled; this.outputDivisor = (shaderInfo.outputDivisor === undef) ? 1 : shaderInfo.outputDivisor; this.shader = new Shader(shaderInfo.shader_vertex, shaderInfo.shader_fragment); this.shader.use(); // set defaults this.shader.addUVArray("aTex"); this.shader.addVertexArray("aVertex"); this.shader.addInt("srcTex", 0); this.shader.addInt("captureTex", 1); this.shader.addVector("texel"); if (this.init !== null) { this.init(this.shader); } } /* New post-process shader chain -- to replace postProcessFX */ function PostProcessChain(width, height, accum) { var gl = GLCore.gl; this.width = width; this.height = height; this.accum = (accum === undef)?false:true; this.vTexel = [1.0 / this.width, 1.0 / this.height, 0]; // buffers this.captureBuffer = new RenderBuffer(width, height, true); this.bufferA = new RenderBuffer(width, height, false); this.bufferB = new RenderBuffer(width, height, false); this.bufferC = new RenderBuffer(width, height, false); this.accumOpacity = 1.0; this.accumIntensity = 0.3; if (this.accum) { this.accumBuffer = new RenderBuffer(width, height, false); this.accumBuffer.use(); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); this.blur_shader = new PostProcessShader({ shader_vertex: ["attribute vec3 aVertex;", "attribute vec2 aTex;", "varying vec2 vTex;", "void main(void)", "{", "vTex = aTex;", "vec4 vPos = vec4(aVertex.xyz,1.0);", "gl_Position = vPos;", "}"].join("\n"), shader_fragment: ["#ifdef GL_ES", "precision highp float;", "#endif", "uniform sampler2D srcTex;", "varying vec2 vTex;", "uniform float opacity;", "void main(void)", "{ gl_FragColor = vec4(texture2D(srcTex, vTex).rgb, opacity);", "}"].join("\n"), init: function(shader) { shader.addFloat("opacity"); shader.setFloat("opacity",1.0); }}); } this.bufferA.use(); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); this.bufferB.use(); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); this.end(); // quad this.fsQuad = this.makeFSQuad(this.width, this.height); this.shaders = []; this.copy_shader = new PostProcessShader({ shader_vertex: ["attribute vec3 aVertex;", "attribute vec2 aTex;", "varying vec2 vTex;", "void main(void) {", "vTex = aTex;", "vec4 vPos = vec4(aVertex.xyz,1.0);", "gl_Position = vPos;", "}"].join("\n"), shader_fragment: [ "#ifdef GL_ES", "precision highp float;", "#endif", "uniform sampler2D srcTex;", "varying vec2 vTex;", "void main(void) {", "gl_FragColor = texture2D(srcTex, vTex);", "}"].join("\n") }); this.resize(width, height); } PostProcessChain.prototype.setBlurOpacity = function (opacity) { this.accumOpacity = opacity; } PostProcessChain.prototype.setBlurIntensity = function (intensity) { this.accumIntensity = intensity; } PostProcessChain.prototype.makeFSQuad = makeFSQuad = function(width, height) { var gl = GLCore.gl; var fsQuad = []; // intentional empty object var w = width; var h = height; var uscale = (width / w); var vscale = (height / h); fsQuad.vbo_points = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0]); fsQuad.vbo_uvs = new Float32Array([0, 0, uscale, 0, uscale, vscale, 0, vscale, 0, 0, uscale, vscale]); fsQuad.gl_points = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, fsQuad.gl_points); gl.bufferData(gl.ARRAY_BUFFER, fsQuad.vbo_points, gl.STATIC_DRAW); fsQuad.gl_uvs = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, fsQuad.gl_uvs); gl.bufferData(gl.ARRAY_BUFFER, fsQuad.vbo_uvs, gl.STATIC_DRAW); return fsQuad; }; PostProcessChain.prototype.destroyFSQuad = destroyFSQuad = function(fsQuad) { var gl = GLCore.gl; gl.deleteBuffer(fsQuad.gl_points); gl.deleteBuffer(fsQuad.gl_uvs); }; PostProcessChain.prototype.renderFSQuad = renderFSQuad = function(shader, fsq) { var gl = GLCore.gl; shader.use(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindBuffer(gl.ARRAY_BUFFER, fsq.gl_points); gl.vertexAttribPointer(shader.aVertex, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(shader.aVertex); gl.bindBuffer(gl.ARRAY_BUFFER, fsq.gl_uvs); gl.vertexAttribPointer(shader.aTex, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(shader.aTex); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.drawArrays(gl.TRIANGLES, 0, 6); }; PostProcessChain.prototype.addShader = function(shader) { this.shaders[this.shaders.length] = shader; shader.shader.use(); shader.shader.setVector("texel", this.vTexel); if (shader.outputDivisor && shader.outputDivisor != 1) { if (postProcessDivisorBuffers[shader.outputDivisor] === undef) var divw = parseInt(this.width/shader.outputDivisor); var divh = parseInt(this.height/shader.outputDivisor); postProcessDivisorBuffers[shader.outputDivisor] = new RenderBuffer(divw, divh, false); postProcessDivisorQuads[shader.outputDivisor] = this.makeFSQuad(divw, divh); } }; PostProcessChain.prototype.resize = function(width, height) { var gl = GLCore.gl; this.width = width; this.height = height; this.vTexel = [1.0 / this.width, 1.0 / this.height, 0]; this.captureBuffer.destroyBuffer(); this.captureBuffer.createBuffer(this.width, this.height, true); this.bufferA.destroyBuffer(); this.bufferA.createBuffer(this.width, this.height, false); this.bufferB.destroyBuffer(); this.bufferB.createBuffer(this.width, this.height, false); this.bufferC.destroyBuffer(); this.bufferC.createBuffer(this.width, this.height, false); if (this.accum) { this.accumBuffer.destroyBuffer(); this.accumBuffer.createBuffer(this.width, this.height, false); this.accumBuffer.use(); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); } for (var p in postProcessDivisorBuffers) { var divw = parseInt(this.width/p); var divh = parseInt(this.height/p); postProcessDivisorBuffers[p].destroyBuffer(); postProcessDivisorBuffers[p].createBuffer(divw, divh, false); this.destroyFSQuad(postProcessDivisorQuads[p]); postProcessDivisorQuads[p] = this.makeFSQuad(divw, divh); } this.inputBuffer = this.bufferA; this.outputBuffer = this.bufferB; for (var i = 0, iMax = this.shaders.length; i < iMax; i++) { this.shaders[i].shader.use(); this.shaders[i].shader.setVector("texel", this.vTexel); if (this.shaders[i].onresize !== null) { this.shaders[i].onresize(this.shaders[i].shader, this.width, this.height); } } this.destroyFSQuad(this.fsQuad); this.fsQuad = this.makeFSQuad(this.width, this.height); }; PostProcessChain.prototype.swap = function() { var t = this.inputBuffer; this.inputBuffer = this.outputBuffer; this.outputBuffer = t; }; PostProcessChain.prototype.begin = function() { this.captureBuffer.use(); }; PostProcessChain.prototype.end = function() { var gl = GLCore.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, null); }; PostProcessChain.prototype.render = function() { var gl = GLCore.gl; var initBuffer = null; this.captureBuffer.texture.use(gl.TEXTURE1); this.outputBuffer.use(); this.captureBuffer.texture.use(gl.TEXTURE0); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); this.renderFSQuad(this.copy_shader.shader, this.fsQuad); this.end(); var c = 0; for (var i = 0, iMax = this.shaders.length; i < iMax; i++) { var s = this.shaders[i]; if (!s.enabled) { continue; } this.swap(); this.inputBuffer.texture.use(gl.TEXTURE0); var o_mode = s.outputMode; //switch (s.outputMode) { if (o_mode === enums.post.output.REPLACE) { //case enums.post.output.REPLACE: if (s.outputDivisor !== 1) { postProcessDivisorBuffers[s.outputDivisor].use(); } else { this.outputBuffer.use(); } //if gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); //break; } else if (o_mode === enums.post.output.ADD || o_mode === enums.post.output.BLEND) { //case enums.post.output.ADD: //case enums.post.output.BLEND: if (s.outputDivisor !== 1) { postProcessDivisorBuffers[s.outputDivisor].use(); } else { this.bufferC.use(); } //if gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); //break; } //if if (s.onupdate !== null) { s.shader.use(); s.onupdate(s.shader); } //if if (s.outputDivisor !== 1) { gl.viewport(0, 0, postProcessDivisorBuffers[s.outputDivisor].width, postProcessDivisorBuffers[s.outputDivisor].height); this.renderFSQuad(s.shader, postProcessDivisorQuads[s.outputDivisor]); if (s.outputMode === enums.post.output.REPLACE) { this.outputBuffer.use(); postProcessDivisorBuffers[s.outputDivisor].texture.use(gl.TEXTURE0); gl.viewport(0, 0, this.width, this.height); this.renderFSQuad(this.copy_shader.shader, this.fsQuad); } else { gl.viewport(0, 0, this.width, this.height); } //if } else { this.renderFSQuad(s.shader, this.fsQuad); } //if //switch (s.outputMode) { //case enums.post.output.REPLACE: // break; if (o_mode === enums.post.output.BLEND) { //case enums.post.output.BLEND: this.swap(); this.outputBuffer.use(); gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); this.inputBuffer.texture.use(gl.TEXTURE0); if (s.outputDivisor !== 1) { postProcessDivisorBuffers[s.outputDivisor].texture.use(gl.TEXTURE0); } else { this.bufferC.texture.use(gl.TEXTURE0); } //if this.renderFSQuad(this.copy_shader.shader, this.fsQuad); gl.disable(gl.BLEND); //break; } else if (o_mode === enums.post.output.ADD) { //case enums.post.output.ADD: this.swap(); this.outputBuffer.use(); gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE); if (s.outputDivisor !== 1) { postProcessDivisorBuffers[s.outputDivisor].texture.use(gl.TEXTURE0); } else { this.bufferC.texture.use(gl.TEXTURE0); } //if this.renderFSQuad(this.copy_shader.shader, this.fsQuad); gl.disable(gl.BLEND); //break; } //if this.end(); c++; } //for if (c === 0) { this.captureBuffer.texture.use(gl.TEXTURE0); } else { this.outputBuffer.texture.use(gl.TEXTURE0); } //if if (this.accum && this.accumOpacity !== 1.0) { this.blur_shader.shader.use(); this.blur_shader.shader.setFloat("opacity",this.accumOpacity); this.accumBuffer.use(); gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); this.renderFSQuad(this.blur_shader.shader, this.fsQuad); this.end(); gl.disable(gl.BLEND); this.renderFSQuad(this.copy_shader.shader, this.fsQuad); gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); this.blur_shader.shader.use(); this.blur_shader.shader.setFloat("opacity",this.accumIntensity); this.accumBuffer.texture.use(gl.TEXTURE0); this.renderFSQuad(this.blur_shader.shader, this.fsQuad); gl.disable(gl.BLEND); } else { this.renderFSQuad(this.copy_shader.shader, this.fsQuad); } }; function NormalMapGen(inTex,width,height) { var gl = GLCore.gl; this.width = width; this.height = height; this.srcTex = inTex; this.outTex = new RenderBuffer(width,height); var tw = width, th = height; var isPOT = true; if (tw===1||th===1) { isPOT = false; } else { if (tw !== 1) { while ((tw % 2) === 0) { tw /= 2; } } if (th !== 1) { while ((th % 2) === 0) { th /= 2; } } if (tw > 1) { isPOT = false; } if (th > 1) { isPOT = false; } } var vTexel = [1.0/width,1.0/height,0]; // buffers this.outputBuffer = new RenderBuffer(width,height,false); // quads this.fsQuad = PostProcessChain.prototype.makeFSQuad(width,height); var vs = ["attribute vec3 aVertex;", "attribute vec2 aTex;", "varying vec2 vTex;", "void main(void)", "{", " vTex = aTex;", " vec4 vPos = vec4(aVertex.xyz,1.0);", " gl_Position = vPos;", "}"].join("\n"); // simple convolution test shader shaderNMap = new Shader(vs, ["#ifdef GL_ES", "precision highp float;", "#endif", "uniform sampler2D srcTex;", "varying vec2 vTex;", "uniform vec3 texel;", "void main(void)", "{", " vec3 color;", " color.r = (texture2D(srcTex,vTex + vec2(texel.x,0)).r-texture2D(srcTex,vTex + vec2(-texel.x,0)).r)/2.0 + 0.5;", " color.g = (texture2D(srcTex,vTex + vec2(0,-texel.y)).r-texture2D(srcTex,vTex + vec2(0,texel.y)).r)/2.0 + 0.5;", " color.b = 1.0;", " gl_FragColor.rgb = color;", " gl_FragColor.a = 1.0;", "}"].join("\n")); shaderNMap.use(); shaderNMap.addUVArray("aTex"); shaderNMap.addVertexArray("aVertex"); shaderNMap.addInt("srcTex",0); shaderNMap.addVector("texel"); shaderNMap.setVector("texel",vTexel); this.shaderNorm = shaderNMap; // bind functions to "subclass" a texture this.setFilter=this.outputBuffer.texture.setFilter; this.clear=this.outputBuffer.texture.clear; this.use=this.outputBuffer.texture.use; this.tex_id=this.outputBuffer.texture.tex_id; this.filterType=this.outputBuffer.texture.filterType; this.outTex.use(gl.TEXTURE0); // // if (!isPOT) { // this.setFilter(enums.texture.filter.LINEAR); // 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); // } else { this.setFilter(enums.texture.filter.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) // } } NormalMapGen.prototype.update = function() { var gl = GLCore.gl; var dims = gl.getParameter(gl.VIEWPORT); this.outputBuffer.use(); gl.viewport(0, 0, this.width, this.height); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); this.srcTex.use(gl.TEXTURE0); PostProcessChain.prototype.renderFSQuad(this.shaderNorm,this.fsQuad); // copy the output buffer to the screen via fullscreen quad gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.viewport(dims[0], dims[1], dims[2], dims[3]); } function DeferredBin() { this.meshBin = {}; this.imageBin = {}; this.meshMap = {}; this.imageMap = {}; this.imageBinPtr = {}; this.meshBinPtr = {}; } DeferredBin.prototype.addMesh = function(binId,meshId,meshObj) { if (this.meshBin[binId] === undef) { this.meshBin[binId] = []; if (this.meshBinPtr[binId]===undef) { this.meshBinPtr[binId] = 0; } } if (this.meshMap[meshId] === undef) { this.meshMap[meshId] = meshObj; this.meshBin[binId].push(meshObj); } } DeferredBin.prototype.addImage = function(binId,imageId,imageObj) { if (this.imageBin[binId] === undef) { this.imageBin[binId] = []; if (this.imageBinPtr[binId]===undef) { this.imageBinPtr[binId] = 0; } } if (this.imageMap[imageId] === undef) { this.imageMap[imageId] = imageObj; this.imageBin[binId].push(imageObj); } }; DeferredBin.prototype.getMeshes = function(binId) { return this.meshBin[binId]; }; DeferredBin.prototype.getImages = function(binId) { return this.imageBin[binId]; }; DeferredBin.prototype.rewindMeshes = function(binId) { this.meshBinPtr[binId] = 0; }; DeferredBin.prototype.rewindImages = function(binId) { this.imageBinPtr[binId] = 0; }; DeferredBin.prototype.getNextMesh = function(binId) { var cBin = this.meshBinPtr[binId]; if (cBin 1) { keys.prev = null; keys.next = env.keys[1]; keys = env.keys[1]; } //if for (var keyI=1,maxKeyI=env.keys.length-1; keyI 1) { keys = env.keys[env.keys.length-1]; keys.prev = env.keys[env.keys.length-2]; keys.next = null; } //if env.firstKey = env.keys[0]; env.lastKey = env.keys[env.keys.length-1]; env.keys = env.firstKey; var envelope = new Envelope(); copyObjectFromJSON(env, envelope); new_con[k]=envelope; } //for k new_controllers[j] = new_con; } //for j obj.motion.controllers = new_controllers; var motion = new Motion(); copyObjectFromJSON(obj.motion, motion); obj.motion = motion; } //if } //reassembleMotion for (var i=0, maxI=scene.sceneObjects.length; i 0) { deferred_bin.addMesh(meshUrl,meshUrl+":"+mesh.id,mesh) for (var f=0,maxF=mesh.faces.length; f 0) { sceneObject.children = []; createChildren(scene_obj, sceneObject); } //if return sceneObject; } //createSceneObject function createChildren(scene_obj, sceneObject) { if (scene_obj.children) { for (var j=0, maxJ=scene_obj.children.length; j 1) { j[tn] = j[tn] || []; j[tn].push({}); cn.jsonParent = j[tn][j[tn].length - 1]; } else { j[tn] = j[tn] || {}; cn.jsonParent = j[tn]; } nodeStack.push(cn); } else if (cn.nodeType === 3) { if (cn.nodeValue.replace(regEmpty, "") !== "") { j.$ = j.$ || ""; j.$ += cn.nodeValue; } } } } return jsonData; } var collada_tools = { fixuaxis: function (up_axis, v) { if (up_axis === 0) { // untested return [v[1], v[0], v[2]]; } else if (up_axis === 1) { return v; } else if (up_axis === 2) { return [v[0], v[2], -v[1]]; } }, fixscaleaxis: function (up_axis, v) { if (up_axis === 0) { // untested return [v[1], v[0], v[2]]; } else if (up_axis === 1) { return v; } else if (up_axis === 2) { return [v[0], v[2], v[1]]; } }, fixukaxis: function (up_axis, mot, chan, val) { // if (mot === enums.motion.POS && chan === enums.motion.Y && up_axis === enums.motion.Z) return -val; if (mot === enums.motion.POS && chan === enums.motion.Z && up_axis === enums.motion.Z) { return -val; } return val; }, getAllOf: function (root_node, leaf_name) { var nStack = [root_node]; var results = []; while (nStack.length) { var n = nStack.pop(); for (var i in n) { if (!n.hasOwnProperty(i)) continue; if (i === leaf_name) { if (n[i].length) { for (var p = 0, pMax = n[i].length; p < pMax; p++) { results.push(n[i][p]); } } else { results.push(n[i]); } } if (typeof(n[i]) == 'object') { if (n[i].length) { for (var p = 0, pMax = n[i].length; p < pMax; p++) { nStack.push(n[i][p]); } } else { nStack.push(n[i]); } } } } return results; }, quaternionFilterZYYZ: function (rot, ofs) { var r = rot; var temp_q = new Quaternion(); if (ofs !== undef) { r = vec3.add(rot, ofs); } temp_q.fromEuler(r[0], r[2], -r[1]); return temp_q.toEuler(); }, cl_getInitalTransform: function (up_axis, scene_node) { var retObj = { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] }; var translate = scene_node.translate; var rotate = scene_node.rotate; var scale = scene_node.scale; if (translate) { retObj.position = collada_tools.fixuaxis(up_axis, util.floatDelimArray(translate.$, " ")); } if (rotate) { for (var r = 0, rMax = rotate.length; r < rMax; r++) { var cl_rot = rotate[r]; var rType = cl_rot["@sid"]; var rVal = util.floatDelimArray(cl_rot.$, " "); if (rType == "rotateX" || rType == "rotationX") { retObj.rotation[0] = rVal[3]; } else if (rType == "rotateY" || rType == "rotationY") { retObj.rotation[1] = rVal[3]; } else if (rType == "rotateZ" || rType == "rotationZ") { retObj.rotation[2] = rVal[3]; } //if } //for } //if if (scale) { retObj.scale = collada_tools.fixscaleaxis(up_axis, util.floatDelimArray(scale.$, " ")); } // var cl_matrix = scene_node.getElementsByTagName("matrix"); // // if (cl_matrix.length) // { // console.log(util.collectTextNode(cl_matrix[0])); // } return retObj; } }; function cubicvr_parseCollada(meshUrl, prefix, deferred_bin) { // if (MeshPool[meshUrl] !== undef) return MeshPool[meshUrl]; var obj = new Mesh(); var scene = new Scene(); var cl = util.getXML(meshUrl); var tech; var sourceId; var materialRef, nameRef, nFace, meshName; var norm, vert, uv, mapLen, computedLen; var i, iCount, iMax, iMod, mCount, mMax, k, kMax, cCount, cMax, sCount, sMax, pCount, pMax, j, jMax; var cl_source = xml2badgerfish(cl); cl = null; if (!cl_source.COLLADA) { throw new Error(meshUrl + " does not appear to be a valid COLLADA file."); } cl_source = cl_source.COLLADA; var clib = { up_axis: 1, images: [], effects: [], materials: [], meshes: [], scenes: [], lights: [], cameras: [], animations: [], }; // var up_axis = 1; // Y if (cl_source.asset) { var sAxis = cl_source.asset.up_axis.$; if (sAxis === "X_UP") { clib.up_axis = 0; } else if (sAxis === "Y_UP") { clib.up_axis = 1; } else if (sAxis === "Z_UP") { clib.up_axis = 2; } } var up_axis = clib.up_axis; if (cl_source.library_images) if (cl_source.library_images.image.length) { var cl_images = cl_source.library_images.image; for (var imgCount = 0, imgCountMax = cl_images.length; imgCount < imgCountMax; imgCount++) { var cl_img = cl_images[imgCount]; var imageId = cl_img["@id"]; var imageName = cl_img["@name"]; var cl_imgsrc = cl_img.init_from; if (cl_imgsrc.$) { var imageSource = cl_imgsrc.$; if (prefix !== undef && (imageSource.lastIndexOf("/") !== -1)) { imageSource = imageSource.substr(imageSource.lastIndexOf("/") + 1); } if (prefix !== undef && (imageSource.lastIndexOf("\\") !== -1)) { imageSource = imageSource.substr(imageSource.lastIndexOf("\\") + 1); } // console.log("Image reference: "+imageSource+" @"+imageId+":"+imageName); clib.images[imageId] = { source: imageSource, id: imageId, name: imageName }; } } } // Effects var effectId; var effectCount, effectMax; var tCount, tMax, inpCount, inpMax; var cl_params, cl_inputs, cl_input, cl_inputmap, cl_samplers, cl_camera, cl_cameras, cl_scene; var ofs; if (cl_source.library_effects) { var cl_effects = cl_source.library_effects.effect; if (cl_effects && !cl_effects.length) cl_effects = [cl_effects]; for (effectCount = 0, effectMax = cl_effects.length; effectCount < effectMax; effectCount++) { var cl_effect = cl_effects[effectCount]; effectId = cl_effect["@id"]; var effect = {}; effect.id = effectId; effect.surfaces = []; effect.samplers = []; cl_params = cl_effect.profile_COMMON.newparam; if (cl_params && !cl_params.length) { cl_params = [cl_params]; }; var params = []; var cl_init; if (cl_params) { for (pCount = 0, pMax = cl_params.length; pCount < pMax; pCount++) { var cl_param = cl_params[pCount]; var paramId = cl_param["@sid"]; if (cl_param.surface) { effect.surfaces[paramId] = {}; var initFrom = cl_param.surface.init_from.$; if (typeof(clib.images[initFrom]) === 'object') { var img_path = prefix + "/" + clib.images[initFrom].source; effect.surfaces[paramId].source = img_path; // console.log(prefix+"/"+clib.images[initFrom].source); } } else if (cl_param.sampler2D) { effect.samplers[paramId] = {}; effect.samplers[paramId].source = cl_param.sampler2D.source.$; if (cl_param.sampler2D.minfilter) { effect.samplers[paramId].minfilter = cl_param.sampler2D.minfilter.$; } if (cl_param.sampler2D.magfilter) { effect.samplers[paramId].magfiter = cl_param.sampler2D.magfilter.$; } } } } var cl_technique = cl_effect.profile_COMMON.technique; if (cl_technique && !cl_technique.length) cl_technique = [cl_technique]; var getColorNode = (function () { return function (n) { var el = n.color; if (!el) { return false; } var cn = n.color; var ar = cn ? util.floatDelimArray(cn.$, " ") : false; return ar; }; }()); var getFloatNode = (function () { return function (n) { var el = n.float; if (!el) { return false; } var cn = n.float; cn = cn ? parseFloat(cn.$) : 0; return cn; }; }()); var getTextureNode = (function () { return function (n) { var el = n.texture; if (!el) { return false; } var cn = n.texture["@texture"]; return cn; }; }()); // effect.material = new Material(effectId); effect.material = { textures_ref: [] } for (tCount = 0, tMax = cl_technique.length; tCount < tMax; tCount++) { // if (cl_technique[tCount].getAttribute("sid") === 'common') { tech = cl_technique[tCount].blinn; if (!tech) { tech = cl_technique[tCount].phong; } if (!tech) { tech = cl_technique[tCount].lambert; } if (tech) { // for (var eCount = 0, eMax = tech[0].childNodes.length; eCount < eMax; eCount++) { // var node = tech[0].childNodes[eCount]; for (var tagName in tech) { var node = tech[tagName]; var c = getColorNode(node); var f = getFloatNode(node); var t = getTextureNode(node); if (c !== false) { if (c.length > 3) { c.pop(); } } if (tagName == "emission") { if (c !== false) { effect.material.ambient = c; } } else if (tagName == "ambient") {} else if (tagName == "diffuse") { if (c !== false) { effect.material.color = c; } } else if (tagName == "specular") { if (c !== false) { effect.material.specular = c; } } else if (tagName == "shininess") { if (f !== false) { effect.material.shininess = f; } } else if (tagName == "reflective") {} else if (tagName == "reflectivity") {} else if (tagName == "transparent") {} else if (tagName == "index_of_refraction") {} // case "transparency": if (f!==false) effect.material.opacity = 1.0-f; break; if (t !== false) { effect.material var srcTex = effect.surfaces[effect.samplers[t].source].source; if (tagName == "emission") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.AMBIENT }); } else if (tagName == "ambient") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.AMBIENT }); } else if (tagName == "diffuse") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.COLOR }); } else if (tagName == "specular") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.SPECULAR }); } else if (tagName == "shininess") {} else if (tagName == "reflective") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.REFLECT }); } else if (tagName == "reflectivity") {} else if (tagName == "transparent") { effect.material.textures_ref.push({ image: srcTex, type: enums.texture.map.ALPHA }); } else if (tagName == "transparency") {} else if (tagName == "index_of_refraction") {} } } } clib.effects[effectId] = effect; } } } // End Effects var cl_lib_mat_inst = collada_tools.getAllOf(cl_source.library_visual_scenes, "instance_material"); var materialMap = []; if (cl_lib_mat_inst.length) { for (i = 0, iMax = cl_lib_mat_inst.length; i < iMax; i++) { var cl_mat_inst = cl_lib_mat_inst[i]; var symbolId = cl_mat_inst["@symbol"]; var targetId = cl_mat_inst["@target"].substr(1); materialMap[symbolId] = targetId; } } var cl_lib_materials = cl_source.library_materials; if (cl_lib_materials.material) { var cl_materials = cl_lib_materials.material; if (cl_materials && !cl_materials.length) cl_materials = [cl_materials]; for (mCount = 0, mMax = cl_materials.length; mCount < mMax; mCount++) { var cl_material = cl_materials[mCount]; var materialId = cl_material["@id"]; var materialName = cl_material["@name"]; var cl_einst = cl_material.instance_effect; if (cl_einst) { effectId = cl_einst["@url"].substr(1); clib.materials.push({ id: materialId, name: materialName, mat: clib.effects[effectId].material }); } } } var cl_lib_geo = cl_source.library_geometries; if (cl_lib_geo) { var cl_geo_node = cl_lib_geo.geometry; if (cl_geo_node && !cl_geo_node.length) cl_geo_node = [cl_geo_node]; if (cl_geo_node.length) { for (var meshCount = 0, meshMax = cl_geo_node.length; meshCount < meshMax; meshCount++) { var meshData = { id: undef, points: [], parts: [] }; var currentMaterial; var cl_geomesh = cl_geo_node[meshCount].mesh; // console.log("found "+meshUrl+"@"+meshName); if (cl_geomesh) { var meshId = cl_geo_node[meshCount]["@id"]; meshName = cl_geo_node[meshCount]["@name"]; // MeshPool[meshUrl + "@" + meshName] = newObj; var cl_geosources = cl_geomesh.source; if (cl_geosources && !cl_geosources.length) cl_geosources = [cl_geosources]; var geoSources = []; for (var sourceCount = 0, sourceMax = cl_geosources.length; sourceCount < sourceMax; sourceCount++) { var cl_geosource = cl_geosources[sourceCount]; sourceId = cl_geosource["@id"]; var sourceName = cl_geosource["@name"]; var cl_floatarray = cl_geosource.float_array; if (cl_floatarray) { geoSources[sourceId] = { id: sourceId, name: sourceName, data: util.floatDelimArray(cl_floatarray.$?cl_floatarray.$:"", " ") }; } var cl_accessor = cl_geosource.technique_common.accessor; if (cl_accessor) { geoSources[sourceId].count = parseInt(cl_accessor["@count"]); geoSources[sourceId].stride = parseInt(cl_accessor["@stride"]); if (geoSources[sourceId].count) { geoSources[sourceId].data = util.repackArray(geoSources[sourceId].data, geoSources[sourceId].stride, geoSources[sourceId].count); } } } var geoVerticies = []; var cl_vertices = cl_geomesh.vertices; var pointRef = null; var pointRefId = null; var triangleRef = null; var normalRef = null; var uvRef = null; if (cl_vertices) { pointRefId = cl_vertices["@id"]; cl_inputs = cl_vertices.input; if (cl_inputs && !cl_inputs.length) cl_inputs = [cl_inputs]; if (cl_inputs) { for (inpCount = 0, inpMax = cl_inputs.length; inpCount < inpMax; inpCount++) { cl_input = cl_inputs[inpCount]; if (cl_input["@semantic"] === "POSITION") { pointRef = cl_input["@source"].substr(1); } } } } var CL_VERTEX = 0, CL_NORMAL = 1, CL_TEXCOORD = 2, CL_OTHER = 3; var cl_triangles = cl_geomesh.triangles; if (cl_triangles && !cl_triangles.length) cl_triangles = [cl_triangles]; var v_c = false, n_c = false, u_c = false; if (cl_triangles) { for (tCount = 0, tMax = cl_triangles.length; tCount < tMax; tCount++) { var meshPart = { material: 0, faces: [], normals: [], texcoords: [] } var cl_trianglesCount = parseInt(cl_triangles[tCount]["@count"], 10); cl_inputs = cl_triangles[tCount].input; if (cl_inputs && !cl_inputs.length) cl_inputs = [cl_inputs]; cl_inputmap = []; if (cl_inputs.length) { for (inpCount = 0, inpMax = cl_inputs.length; inpCount < inpMax; inpCount++) { cl_input = cl_inputs[inpCount]; ofs = parseInt(cl_input["@offset"], 10); nameRef = cl_input["@source"].substr(1); if (cl_input["@semantic"] === "VERTEX") { if (nameRef === pointRefId) { nameRef = triangleRef = pointRef; } else { triangleRef = nameRef; } v_c = true; cl_inputmap[ofs] = CL_VERTEX; } else if (cl_input["@semantic"] === "NORMAL") { normalRef = nameRef; if (geoSources[normalRef].count) { cl_inputmap[ofs] = CL_NORMAL; } n_c = true; } else if (cl_input["@semantic"] === "TEXCOORD") { uvRef = nameRef; if (geoSources[uvRef].count) { cl_inputmap[ofs] = CL_TEXCOORD; } u_c = true; } else { cl_inputmap[ofs] = CL_OTHER; } } } mapLen = cl_inputmap.length; materialRef = cl_triangles[tCount]["@material"]; if (materialRef === null) { meshPart.material = 0; } else { if (materialMap[materialRef] === undef) { log("missing material [" + materialRef + "]@" + meshName + "?"); meshPart.material = 0; } else { meshPart.material = materialMap[materialRef]; } } var cl_triangle_source = cl_triangles[tCount].p; var triangleData = []; if (cl_triangle_source) { triangleData = util.intDelimArray(cl_triangle_source.$, " "); } if (triangleData.length) { computedLen = ((triangleData.length) / cl_inputmap.length) / 3; if (computedLen !== cl_trianglesCount) { // console.log("triangle data doesn't add up, skipping object load: "+computedLen+" !== "+cl_trianglesCount); } else { if (meshData.points.length === 0) { meshData.points = geoSources[pointRef].data; } ofs = 0; for (i = 0, iMax = triangleData.length, iMod = cl_inputmap.length; i < iMax; i += iMod * 3) { norm = []; vert = []; uv = []; for (j = 0; j < iMod * 3; j++) { var jMod = j % iMod; if (cl_inputmap[jMod] === CL_VERTEX) { vert.push(triangleData[i + j]); } else if (cl_inputmap[jMod] === CL_NORMAL) { norm.push(triangleData[i + j]); } else if (cl_inputmap[jMod] === CL_TEXCOORD) { uv.push(triangleData[i + j]); } } if (vert.length) { meshPart.faces.push(vert); if (norm.length === 3) { meshPart.normals.push([collada_tools.fixuaxis(clib.up_axis, geoSources[normalRef].data[norm[0]]), collada_tools.fixuaxis(clib.up_axis, geoSources[normalRef].data[norm[1]]), collada_tools.fixuaxis(clib.up_axis, geoSources[normalRef].data[norm[2]])]); } if (uv.length === 3) { meshPart.texcoords.push([geoSources[uvRef].data[uv[0]], geoSources[uvRef].data[uv[1]], geoSources[uvRef].data[uv[2]]]); } } } } } meshData.parts.push(meshPart); } } var cl_polylist = cl_geomesh.polylist; if (!cl_polylist) { cl_polylist = cl_geomesh.polygons; // try polygons } if (cl_polylist && !cl_polylist.length) cl_polylist = [cl_polylist]; if (cl_polylist) { for (tCount = 0, tMax = cl_polylist.length; tCount < tMax; tCount++) { var meshPart = { material: 0, faces: [], normals: [], texcoords: [] } var cl_polylistCount = parseInt(cl_polylist[tCount]["@count"], 10); cl_inputs = cl_polylist[tCount].input; if (cl_inputs && !cl_inputs.length) cl_inputs = [cl_inputs]; cl_inputmap = []; if (cl_inputs.length) { for (inpCount = 0, inpMax = cl_inputs.length; inpCount < inpMax; inpCount++) { cl_input = cl_inputs[inpCount]; var cl_ofs = cl_input["@offset"]; if (cl_ofs === null) { cl_ofs = cl_input["@idx"]; } ofs = parseInt(cl_ofs, 10); nameRef = cl_input["@source"].substr(1); if (cl_input["@semantic"] === "VERTEX") { if (nameRef === pointRefId) { nameRef = triangleRef = pointRef; } else { triangleRef = nameRef; } cl_inputmap[ofs] = CL_VERTEX; } else if (cl_input["@semantic"] === "NORMAL") { normalRef = nameRef; cl_inputmap[ofs] = CL_NORMAL; } else if (cl_input["@semantic"] === "TEXCOORD") { uvRef = nameRef; cl_inputmap[ofs] = CL_TEXCOORD; } else { cl_inputmap[ofs] = CL_OTHER; } } } var cl_vcount = cl_polylist[tCount].vcount; var vcount = []; if (cl_vcount) { vcount = util.intDelimArray(cl_vcount.$, " "); } materialRef = cl_polylist[tCount]["@material"]; if (materialRef === undef) { meshPart.material = 0; } else { meshPart.material = materialMap[materialRef]; } var cl_poly_source = cl_polylist[tCount].p; mapLen = cl_inputmap.length; var polyData = []; if ((cl_poly_source.length > 1) && !vcount.length) // blender 2.49 style { var pText = ""; for (pCount = 0, pMax = cl_poly_source.length; pCount < pMax; pCount++) { var tmp = util.intDelimArray(cl_poly_source[pCount].$, " "); vcount[pCount] = parseInt(tmp.length / mapLen, 10); polyData.splice(polyData.length, 0, tmp); } } else { if (cl_poly_source) { polyData = util.intDelimArray(cl_poly_source.$, " "); } } if (polyData.length) { computedLen = vcount.length; if (computedLen !== cl_polylistCount) { log("poly vcount data doesn't add up, skipping object load: " + computedLen + " !== " + cl_polylistCount); } else { if (meshData.points.length === 0) { meshData.points = geoSources[pointRef].data; } ofs = 0; for (i = 0, iMax = vcount.length; i < iMax; i++) { norm = []; vert = []; uv = []; for (j = 0, jMax = vcount[i] * mapLen; j < jMax; j++) { if (cl_inputmap[j % mapLen] === CL_VERTEX) { vert.push(polyData[ofs]); ofs++; } else if (cl_inputmap[j % mapLen] === CL_NORMAL) { norm.push(polyData[ofs]); ofs++; } else if (cl_inputmap[j % mapLen] === CL_TEXCOORD) { uv.push(polyData[ofs]); ofs++; } } if (vert.length) { // if (up_axis !== 1) // { // vert.reverse(); // } // nFace = newObj.addFace(vert); meshPart.faces.push(vert); if (norm.length) { var nlist = []; for (k = 0, kMax = norm.length; k < kMax; k++) { // newObj.faces[nFace].point_normals[k] = fixuaxis(geoSources[normalRef].data[norm[k]]); nlist.push(collada_tools.fixuaxis(clib.up_axis, geoSources[normalRef].data[norm[k]])); } meshPart.normals.push(nlist); } if (uv.length) { var tlist = []; for (k = 0, kMax = uv.length; k < kMax; k++) { // newObj.faces[nFace].uvs[k] = geoSources[uvRef].data[uv[k]]; tlist.push(geoSources[uvRef].data[uv[k]]); } meshPart.texcoords.push(tlist); } } } } } } } if (up_axis !== 1) { for (i = 0, iMax = meshData.points.length; i < iMax; i++) { meshData.points[i] = collada_tools.fixuaxis(clib.up_axis, meshData.points[i]); } } meshData.id = meshId; clib.meshes.push(meshData); } } } } var cl_lib_cameras = cl_source.library_cameras; var camerasBoundRef = []; if (cl_lib_cameras) { cl_cameras = cl_lib_cameras.camera; if (cl_cameras && !cl_cameras.length) cl_cameras = [cl_cameras]; for (cCount = 0, cMax = cl_cameras.length; cCount < cMax; cCount++) { cl_camera = cl_cameras[cCount]; var cameraId = cl_camera["@id"]; var cameraName = cl_camera["@name"]; // var cl_perspective = cl_camera.getElementsByTagName("perspective"); // if (cl_perspective.length) { // var perspective = cl_perspective[0]; var cl_yfov = 0; var cl_znear = 0; var cl_zfar = 0; if (cl_camera.optics) if (cl_camera.optics.technique_common) if (cl_camera.optics.technique_common.perspective) { cl_yfov = cl_camera.optics.technique_common.perspective.yfov; cl_znear = cl_camera.optics.technique_common.perspective.znear; cl_zfar = cl_camera.optics.technique_common.perspective.zfar; } var yfov; var znear; var zfar; if (!cl_yfov && !cl_znear && !cl_zfar) { cl_params = cl_camera.param; if (cl_params && !cl_params.length) cl_params = [cl_params]; for (i = 0, iMax = cl_params.length; i < iMax; i++) { var txt = cl_params[i].$; var pName = cl_params[i]["@name"]; if (pName == "YFOV") { yfov = parseFloat(txt); } else if (pName == "ZNEAR") { znear = parseFloat(txt); } else if (pName == "ZFAR") { zfar = parseFloat(txt); } } } else { yfov = cl_yfov ? parseFloat(cl_yfov.$) : 60; znear = cl_znear ? parseFloat(cl_znear.$) : 0.1; zfar = cl_zfar ? parseFloat(cl_zfar.$) : 1000.0; } clib.cameras.push({ id: cameraId, targeted: false, fov: parseFloat(yfov), nearclip: parseFloat(znear), farclip: parseFloat(zfar) }); } } var cl_lib_lights = cl_source.library_lights; if (cl_lib_lights) { var cl_lights = cl_lib_lights.light; if (cl_lights && !cl_lights.length) cl_lights = [cl_lights]; if (cl_lights) for (var lightCount = 0, lightMax = cl_lights.length; lightCount < lightMax; lightCount++) { var cl_light = cl_lights[lightCount]; var cl_point = cl_light.technique_common.point; var cl_pointLight = cl_point ? cl_point : null; var lightId = cl_light["@id"]; var lightName = cl_light["@name"]; if (cl_pointLight !== null) { var cl_intensity = cl_pointLight.intensity; var intensity = cl_intensity ? parseFloat(cl_intensity.$) : 1.0; var cl_distance = cl_pointLight.distance; var distance = cl_distance ? parseFloat(cl_distance.$) : 10.0; var cl_color = cl_pointLight.color; var color = [1, 1, 1]; if (cl_color) { color = util.floatDelimArray(cl_color.$, " "); } clib.lights.push({ id: lightId, name: lightId, type: enums.light.type.POINT, method: enums.light.method.STATIC, diffuse: color, specular: [0, 0, 0], distance: distance, intensity: intensity }); } } } var cl_lib_scenes = cl_source.library_visual_scenes; if (cl_lib_scenes) { var cl_scenes = null; cl_scenes = cl_lib_scenes.visual_scene; if (cl_scenes && !cl_scenes.length) cl_scenes = [cl_scenes]; for (var sceneCount = 0, sceneMax = cl_scenes.length; sceneCount < sceneMax; sceneCount++) { cl_scene = cl_scenes[sceneCount]; var sceneId = cl_scene["@id"]; var sceneName = cl_scene["@name"]; var sceneData = { id: sceneName, sceneObjects: [], cameras: [], lights: [], parentMap: [] }; var nodeMap = {}; var cl_nodes = []; var cl_stack = [cl_scene]; while (cl_stack.length) { var ntemp = cl_stack.pop(); if (ntemp.node) { var nlist = ntemp.node; if (nlist && !nlist.length) nlist = [nlist]; if (nlist) { for (var i = 0, iMax = nlist.length; i < iMax; i++) { nlist[i].parentNode = ntemp; cl_nodes.push(nlist[i]); cl_stack.push(nlist[i]); } } } } if (cl_nodes.length) { for (var nodeCount = 0, nodeMax = cl_nodes.length; nodeCount < nodeMax; nodeCount++) { var cl_node = cl_nodes[nodeCount]; var cl_geom = cl_node.instance_geometry; var cl_light = cl_nodes[nodeCount].instance_light; cl_camera = cl_nodes[nodeCount].instance_camera; var nodeId = cl_node["@id"]; var nodeName = cl_node["@name"]; var it = collada_tools.cl_getInitalTransform(clib.up_axis, cl_node); if (up_axis === 2) { it.rotation = collada_tools.quaternionFilterZYYZ(it.rotation, (cl_camera) ? [-90, 0, 0] : undef); } var sceneObject = {}; if (cl_geom) { meshName = cl_geom["@url"].substr(1); sceneObject.name = sceneObject.id = (nodeName) ? nodeName : nodeId; sceneObject.position = it.position; sceneObject.rotation = it.rotation; sceneObject.scale = it.scale; sceneObject.meshId = meshName; sceneData.sceneObjects.push(sceneObject); nodeMap[sceneObject.id] = true;; if (cl_node.parentNode) { var parentNodeId = cl_node.parentNode["@id"]; var parentNodeName = cl_node.parentNode["@name"]; if (parentNodeId) { if (nodeMap[parentNodeId]) { sceneData.parentMap.push({ parent: parentNodeId, child: sceneObject.id }); } } } } else if (cl_camera) { var cam_instance = cl_camera; var camRefId = cam_instance["@url"].substr(1); sceneData.cameras.push({ name: (nodeName) ? nodeName : nodeId, id: (nodeName) ? nodeName : nodeId, source: camRefId, position: it.position, rotation: it.rotation }); } else if (cl_light) { var lightRefId = cl_light["@url"].substr(1); sceneData.lights.push({ name: (nodeName) ? nodeName : nodeId, id: (nodeName) ? nodeName : nodeId, source: lightRefId, position: it.position }); } else { sceneData.sceneObjects.push({ id: (nodeName !== null) ? nodeName : nodeId, name: (nodeName !== null) ? nodeName : nodeId, position: it.position, rotation: it.rotation, scale: it.scale }); } } } clib.scenes.push(sceneData); } } var cl_lib_anim = cl_source.library_animations; var animId; if (cl_lib_anim) { var cl_anim_sources = cl_lib_anim.animation; if (cl_anim_sources && !cl_anim_sources.length) cl_anim_sources = [cl_anim_sources]; if (cl_anim_sources) { for (var aCount = 0, aMax = cl_anim_sources.length; aCount < aMax; aCount++) { var cl_anim = cl_anim_sources[aCount]; animId = cl_anim["@id"]; var animName = cl_anim["@name"]; clib.animations[animId] = {}; clib.animations[animId].sources = []; var cl_sources = cl_anim.source; if (cl_sources && !cl_sources.length) cl_sources = [cl_sources]; if (cl_sources.length) { for (sCount = 0, sMax = cl_sources.length; sCount < sMax; sCount++) { var cl_csource = cl_sources[sCount]; sourceId = cl_csource["@id"]; var tech_common = cl_csource.technique_common; var name_array = null; var float_array = null; var data = null; if (cl_csource.name_array) { name_array = util.textDelimArray(cl_csource.name_array.$, " "); } else if (cl_csource.Name_array) { name_array = util.textDelimArray(cl_csource.Name_array.$, " "); } else if (cl_csource.float_array) { float_array = util.floatDelimArray(cl_csource.float_array.$, " "); } var acCount = 0; var acSource = ""; var acStride = 1; if (tech_common) { tech = tech_common; var acc = tech.accessor; acCount = parseInt(acc["@count"], 10); acSource = acc["@source"].substr(1); var aStride = acc["@stride"]; if (aStride) { acStride = parseInt(aStride, 10); } } clib.animations[animId].sources[sourceId] = { data: name_array ? name_array : float_array, count: acCount, source: acSource, stride: acStride }; if (acStride !== 1) { clib.animations[animId].sources[sourceId].data = util.repackArray(clib.animations[animId].sources[sourceId].data, acStride, acCount); } } } cl_samplers = cl_anim.sampler; if (cl_samplers && !cl_samplers.length) cl_samplers = [cl_samplers]; if (cl_samplers) { clib.animations[animId].samplers = []; for (sCount = 0, sMax = cl_samplers.length; sCount < sMax; sCount++) { var cl_sampler = cl_samplers[sCount]; var samplerId = cl_sampler["@id"]; cl_inputs = cl_sampler.input; if (cl_inputs && !cl_inputs.length) cl_inputs = [cl_inputs]; if (cl_inputs) { var inputs = []; for (iCount = 0, iMax = cl_inputs.length; iCount < iMax; iCount++) { cl_input = cl_inputs[iCount]; var semanticName = cl_input["@semantic"]; inputs[semanticName] = cl_input["@source"].substr(1); } clib.animations[animId].samplers[samplerId] = inputs; } } } var cl_channels = cl_anim.channel; if (cl_channels && !cl_channels.length) cl_channels = [cl_channels]; if (cl_channels) { clib.animations[animId].channels = []; for (cCount = 0, cMax = cl_channels.length; cCount < cMax; cCount++) { var channel = cl_channels[cCount]; var channelSource = channel["@source"].substr(1); var channelTarget = channel["@target"]; var channelSplitA = channelTarget.split("/"); var channelTargetName = channelSplitA[0]; var channelSplitB = channelSplitA[1].split("."); var channelParam = channelSplitB[0]; var channelType = channelSplitB[1]; clib.animations[animId].channels.push({ source: channelSource, target: channelTarget, targetName: channelTargetName, paramName: channelParam, typeName: channelType }); } } } } } var cl_lib_scene = cl_source.scene; if (cl_lib_scene) { cl_scene = cl_lib_scene.instance_visual_scene; if (cl_scene) { var sceneUrl = cl_scene["@url"].substr(1); clib.scene = sceneUrl; } } return clib; } function cubicvr_loadCollada(meshUrl, prefix, deferred_bin) { var clib = cubicvr_parseCollada(meshUrl, prefix, deferred_bin); var up_axis = clib.up_axis; var materialRef = []; for (var m = 0, mMax = clib.materials.length; m < mMax; m++) { var material = clib.materials[m]; var newMaterial = new Material(material.mat); for (var t = 0, tMax = material.mat.textures_ref.length; t < tMax; t++) { var tex = material.mat.textures_ref[t]; var texObj = null; if (Texture_ref[tex.image] === undefined) { texObj = new Texture(tex.image, GLCore.default_filter, deferred_bin, meshUrl); } else { texObj = Textures_obj[Texture_ref[tex.image]]; } newMaterial.setTexture(texObj, tex.type); } materialRef[material.id] = newMaterial; } var meshRef = []; for (var m = 0, mMax = clib.meshes.length; m < mMax; m++) { var meshData = clib.meshes[m]; var newObj = new Mesh(meshData.id); newObj.points = meshData.points; for (var mp = 0, mpMax = meshData.parts.length; mp < mpMax; mp++) { var part = meshData.parts[mp]; if (part.material !== 0) { newObj.setFaceMaterial(materialRef[part.material]); } var bNorm = part.normals.length ? true : false; var bTex = part.texcoords.length ? true : false; for (var p = 0, pMax = part.faces.length; p < pMax; p++) { var faceNum = newObj.addFace(part.faces[p]); if (bNorm) newObj.faces[faceNum].point_normals = part.normals[p]; if (bTex) newObj.faces[faceNum].uvs = part.texcoords[p]; } } // newObj.calcNormals(); if (!deferred_bin) { newObj.triangulateQuads(); newObj.compile(); } else { deferred_bin.addMesh(meshUrl, meshUrl + ":" + meshId, newObj); } meshRef[meshData.id] = newObj; } var camerasRef = []; for (var c = 0, cMax = clib.cameras.length; c < cMax; c++) { camerasRef[clib.cameras[c].id] = clib.cameras[c]; } var lightsRef = []; for (var l = 0, lMax = clib.lights.length; l < lMax; l++) { lightsRef[clib.lights[l].id] = clib.lights[l]; } var sceneObjectMap = {}; var sceneLightMap = {}; var sceneCameraMap = {}; var scenesRef = {}; for (var s = 0, sMax = clib.scenes.length; s < sMax; s++) { var scn = clib.scenes[s]; var newScene = new CubicVR.Scene(); for (var so = 0, soMax = scn.sceneObjects.length; so < soMax; so++) { var sceneObj = scn.sceneObjects[so]; var newSceneObject = new SceneObject(sceneObj); var srcMesh = meshRef[sceneObj.meshId] || null; newSceneObject.obj = srcMesh; sceneObjectMap[sceneObj.id] = newSceneObject; newScene.bindSceneObject(newSceneObject); } for (var l = 0, lMax = scn.lights.length; l < lMax; l++) { var lt = scn.lights[l]; var newLight = new Light(lightsRef[lt.source]); newLight.position = lt.position; sceneLightMap[lt.id] = newLight; newScene.bindLight(newLight); } if (scn.cameras.length) { // single camera for the moment until we support it var cam = scn.cameras[0]; var newCam = new Camera(camerasRef[cam.source]); newCam.position = cam.position; newCam.rotation = cam.rotation; sceneCameraMap[cam.id] = newCam; newScene.camera = newCam; } for (var p = 0, pMax = scn.parentMap.length; p < pMax; p++) { var pmap = scn.parentMap[p]; sceneObjectMap[pmap.parent].bindChild(sceneObjectMap[pmap.child]); } scenesRef[scn.id] = newScene; } for (animId in clib.animations) { if (clib.animations.hasOwnProperty(animId)) { var anim = clib.animations[animId]; if (anim.channels.length) { for (cCount = 0, cMax = anim.channels.length; cCount < cMax; cCount++) { var chan = anim.channels[cCount]; var sampler = anim.samplers[chan.source]; var samplerInput = anim.sources[sampler["INPUT"]]; var samplerOutput = anim.sources[sampler["OUTPUT"]]; var samplerInterp = anim.sources[sampler["INTERPOLATION"]]; var samplerInTangent = anim.sources[sampler["IN_TANGENT"]]; var samplerOutTangent = anim.sources[sampler["OUT_TANGENT"]]; var hasInTangent = (sampler["IN_TANGENT"] !== undef); var hasOutTangent = (sampler["OUT_TANGENT"] !== undef); var mtn = null; var targetSceneObject = sceneObjectMap[chan.targetName]; var targetCamera = sceneCameraMap[chan.targetName]; var targetLight = sceneLightMap[chan.targetName]; if (targetSceneObject) { if (targetSceneObject.motion === null) { targetSceneObject.motion = new Motion(); } mtn = targetSceneObject.motion; } else if (targetCamera) { if (targetCamera.motion === null) { targetCamera.motion = new Motion(); } mtn = targetCamera.motion; } else if (targetLight) { if (targetLight.motion === null) { targetLight.motion = new Motion(); } mtn = targetLight.motion; } // else // { // console.log("missing",chan.targetName); // console.log("missing",chan.paramName); // } if (mtn === null) { continue; } var controlTarget = enums.motion.POS; var motionTarget = enums.motion.X; if (up_axis === 2) { mtn.yzflip = true; } var pName = chan.paramName; if (pName === "rotateX" || pName === "rotationX") { controlTarget = enums.motion.ROT; motionTarget = enums.motion.X; } else if (pName === "rotateY" || pName === "rotationY") { controlTarget = enums.motion.ROT; motionTarget = enums.motion.Y; } else if (pName === "rotateZ" || pName === "rotationZ") { controlTarget = enums.motion.ROT; motionTarget = enums.motion.Z; } else if (pName === "location") { controlTarget = enums.motion.POS; if (chan.typeName === "X") { motionTarget = enums.motion.X; } if (chan.typeName === "Y") { motionTarget = enums.motion.Y; } if (chan.typeName === "Z") { motionTarget = enums.motion.Z; } } else if (pName === "translate") { controlTarget = enums.motion.POS; if (chan.typeName === "X") { motionTarget = enums.motion.X; } if (chan.typeName === "Y") { motionTarget = enums.motion.Y; } if (chan.typeName === "Z") { motionTarget = enums.motion.Z; } } else if (pName === "LENS") { // controlTarget = enums.motion.LENS; // motionTarget = 4; controlTarget = 10; motionTarget = 10; continue; // disabled, only here for temporary collada files } else if (pName === "FOV") { controlTarget = enums.motion.FOV; motionTarget = 3; // ensure no axis fixes are applied } else if (pName === "ZNEAR") { controlTarget = enums.motion.NEARCLIP; motionTarget = 3; // ensure no axis fixes are applied } else if (pName === "ZFAR") { controlTarget = enums.motion.FARCLIP; motionTarget = 3; // ensure no axis fixes are applied } else if (pName === "intensity") { controlTarget = enums.motion.INTENSITY; motionTarget = 3; // ensure no axis fixes are applied } if (targetLight && controlTarget < 3) targetLight.method = enums.light.method.DYNAMIC; // if (up_axis === 2 && motionTarget === enums.motion.Z) motionTarget = enums.motion.Y; // else if (up_axis === 2 && motionTarget === enums.motion.Y) motionTarget = enums.motion.Z; // var ival; for (mCount = 0, mMax = samplerInput.data.length; mCount < mMax; mCount++) { // in the process of being deprecated k = null; if (typeof(samplerOutput.data[mCount]) === 'object') { for (i = 0, iMax = samplerOutput.data[mCount].length; i < iMax; i++) { ival = i; if (up_axis === 2 && i === 2) { ival = 1; } else if (up_axis === 2 && i === 1) { ival = 2; } k = mtn.setKey(controlTarget, ival, samplerInput.data[mCount], collada_tools.fixukaxis(clib.up_axis, controlTarget, ival, samplerOutput.data[mCount][i])); if (samplerInterp) { var pInterp = samplerInterp.data[mCount][i]; if (pInterp === "LINEAR") { k.shape = enums.envelope.shape.LINE; } else if (pInterp === "BEZIER") { if (!(hasInTangent || hasOutTangent)) { k.shape = enums.envelope.shape.LINEAR; } else { k.shape = enums.envelope.shape.BEZI; } } } } } else { ival = motionTarget; ofs = 0; if (targetCamera) { if (controlTarget === enums.motion.ROT) { if (up_axis === 2 && ival === 0) { ofs = -90; } } } if (controlTarget === enums.motion.ROT) { k = mtn.setKey(controlTarget, ival, samplerInput.data[mCount], samplerOutput.data[mCount] + ofs); } else { if (up_axis === 2 && motionTarget === 2) { ival = 1; } else if (up_axis === 2 && motionTarget === 1) { ival = 2; } k = mtn.setKey(controlTarget, ival, samplerInput.data[mCount], collada_tools.fixukaxis(clib.up_axis, controlTarget, ival, samplerOutput.data[mCount])); } if (samplerInterp) { var pInterp = samplerInterp.data[mCount]; if (pInterp === "LINEAR") { k.shape = enums.envelope.shape.LINE; } else if (pInterp === "BEZIER") { if (!(hasInTangent || hasOutTangent)) { k.shape = enums.envelope.shape.LINEAR; k.continutity = 1.0; } else { k.shape = enums.envelope.shape.BEZ2; var itx = samplerInTangent.data[mCount][0], ity; var otx = samplerOutTangent.data[mCount][0], oty; if (controlTarget === enums.motion.ROT) { ity = samplerInTangent.data[mCount][1]; oty = samplerOutTangent.data[mCount][1]; // k.value = k.value/10; // mtn.rscale = 10; k.param[0] = itx - k.time; k.param[1] = ity - k.value + ofs; k.param[2] = otx - k.time; k.param[3] = oty - k.value + ofs; } else { ity = collada_tools.fixukaxis(clib.up_axis, controlTarget, ival, samplerInTangent.data[mCount][1]); oty = collada_tools.fixukaxis(clib.up_axis, controlTarget, ival, samplerOutTangent.data[mCount][1]); k.param[0] = itx - k.time; k.param[1] = ity - k.value; k.param[2] = otx - k.time; k.param[3] = oty - k.value; } } } } } } } } } } var sceneRef = null; if (clib.scene) { sceneRef = scenesRef[clib.scene]; } else { sceneRef = scenesRef.pop(); } return sceneRef; } function GML(srcUrl) { this.strokes = []; this.bounds = [1, 1, 1]; this.origin = [0, 0, 0]; this.upvector = [0, 1, 0]; this.viewvector = [0, 0, 1]; this.manual_pos = 0; if (srcUrl === undef) { return; } var gml = util.getXML(srcUrl); var gml_header = gml.getElementsByTagName("header"); if (!gml_header.length) { return null; } var header = gml_header[0]; var gml_environment = gml.getElementsByTagName("environment"); if (!gml_environment.length) { return null; } this.name = null; var gml_name = header.getElementsByTagName("name"); if (gml_name.length) { this.name = util.collectTextNode(gml_name[0]); } var gml_screenbounds = gml_environment[0].getElementsByTagName("screenBounds"); if (gml_screenbounds.length) { this.bounds = [ parseFloat(util.collectTextNode(gml_screenbounds[0].getElementsByTagName("x")[0])), parseFloat(util.collectTextNode(gml_screenbounds[0].getElementsByTagName("y")[0])), parseFloat(util.collectTextNode(gml_screenbounds[0].getElementsByTagName("z")[0])) ]; } var gml_origin = gml_environment[0].getElementsByTagName("origin"); if (gml_origin.length) { this.origin = [ parseFloat(util.collectTextNode(gml_origin[0].getElementsByTagName("x")[0])), parseFloat(util.collectTextNode(gml_origin[0].getElementsByTagName("y")[0])), parseFloat(util.collectTextNode(gml_origin[0].getElementsByTagName("z")[0])) ]; } var gml_upvector = gml_environment[0].getElementsByTagName("up"); if (gml_upvector.length) { this.upvector = [ parseFloat(util.collectTextNode(gml_upvector[0].getElementsByTagName("x")[0])), parseFloat(util.collectTextNode(gml_upvector[0].getElementsByTagName("y")[0])), parseFloat(util.collectTextNode(gml_upvector[0].getElementsByTagName("z")[0])) ]; } var gml_drawings = gml.getElementsByTagName("drawing"); var drawings = []; for (var dCount = 0, dMax = gml_drawings.length; dCount < dMax; dCount++) { var drawing = gml_drawings[dCount]; var gml_strokes = drawing.getElementsByTagName("stroke"); var xm = 0, ym = 0, zm = 0, tm = 0; for (var sCount = 0, sMax = gml_strokes.length; sCount < sMax; sCount++) { var gml_stroke = gml_strokes[sCount]; var gml_points = gml_stroke.getElementsByTagName("pt"); var plen = gml_points.length; var points = new Array(plen); var px, py, pz, pt; for (var pCount = 0, pMax = plen; pCount < pMax; pCount++) { var gml_point = gml_points[pCount]; px = parseFloat(util.collectTextNode(gml_point.getElementsByTagName("x")[0])); py = parseFloat(util.collectTextNode(gml_point.getElementsByTagName("y")[0])); pz = parseFloat(util.collectTextNode(gml_point.getElementsByTagName("z")[0])); pt = parseFloat(util.collectTextNode(gml_point.getElementsByTagName("time")[0])); if (this.upvector[0] === 1) { points[pCount] = [(py !== py) ? 0 : py, (px !== px) ? 0 : -px, (pz !== pz) ? 0 : pz, pt]; } else if (this.upvector[1] === 1) { points[pCount] = [(px !== px) ? 0 : px, (py !== py) ? 0 : py, (pz !== pz) ? 0 : pz, pt]; } else if (this.upvector[2] === 1) { points[pCount] = [(px !== px) ? 0 : px, (pz !== pz) ? 0 : -pz, (py !== py) ? 0 : py, pt]; } if (xm < px) { xm = px; } if (ym < py) { ym = py; } if (zm < pz) { zm = pz; } if (tm < pt) { tm = pt; } } if (zm > tm) { // fix swapped Z/Time for (var i = 0, iMax = points.length; i < iMax; i++) { var t = points[i][3]; points[i][3] = points[i][2]; points[i][2] = t / this.bounds[2]; } } this.strokes[sCount] = points; } } } GML.prototype.addStroke = function(points, tstep) { var pts = []; if (tstep === undef) { tstep = 0.1; } for (var i = 0, iMax = points.length; i < iMax; i++) { var ta = [points[i][0], points[i][1], points[i][2]]; this.manual_pos += tstep; ta.push(this.manual_pos); pts.push(ta); } this.strokes.push(pts); }; GML.prototype.recenter = function() { var min = [0, 0, 0]; var max = [this.strokes[0][0][0], this.strokes[0][0][1], this.strokes[0][0][2]]; var i, iMax, s, sMax; for (s = 0, sMax = this.strokes.length; s < sMax; s++) { for (i = 0, iMax = this.strokes[s].length; i < iMax; i++) { if (min[0] > this.strokes[s][i][0]) { min[0] = this.strokes[s][i][0]; } if (min[1] > this.strokes[s][i][1]) { min[1] = this.strokes[s][i][1]; } if (min[2] > this.strokes[s][i][2]) { min[2] = this.strokes[s][i][2]; } if (max[0] < this.strokes[s][i][0]) { max[0] = this.strokes[s][i][0]; } if (max[1] < this.strokes[s][i][1]) { max[1] = this.strokes[s][i][1]; } if (max[2] < this.strokes[s][i][2]) { max[2] = this.strokes[s][i][2]; } } } var center = vec3.multiply(vec3.subtract(max, min), 0.5); for (s = 0, sMax = this.strokes.length; s < sMax; s++) { for (i = 0, iMax = this.strokes[s].length; i < iMax; i++) { this.strokes[s][i][0] = this.strokes[s][i][0] - center[0]; this.strokes[s][i][1] = this.strokes[s][i][1] - (this.upvector[1] ? center[1] : (-center[1])); this.strokes[s][i][2] = this.strokes[s][i][2] - center[2]; } } }; GML.prototype.generateObject = function(seg_mod, extrude_depth, pwidth, divsper, do_zmove) { if (seg_mod === undef) { seg_mod = 0; } if (extrude_depth === undef) { extrude_depth = 0; } if (do_zmove === undef) { do_zmove = false; } // temporary defaults var divs = 3; // var divsper = 0.02; if (divsper === undef) divsper = 0.02; // var pwidth = 0.015; if (pwidth === undef) pwidth = 0.015; var extrude = extrude_depth !== 0; var segCount = 0; var faceSegment = 0; var obj = new Mesh(this.name); var lx, ly, lz, lt; var i, iMax, pCount; for (var sCount = 0, sMax = this.strokes.length; sCount < sMax; sCount++) { var strokeEnvX = new Envelope(); var strokeEnvY = new Envelope(); var strokeEnvZ = new Envelope(); var pMax = this.strokes[sCount].length; var d = 0; var len_set = []; var time_set = []; var start_time = 0; var strk = this.strokes[sCount]; for (pCount = 0; pCount < pMax; pCount++) { var pt = strk[pCount]; var k1 = strokeEnvX.addKey(pt[3], pt[0]); var k2 = strokeEnvY.addKey(pt[3], pt[1]); var k3; if (do_zmove) { k3 = strokeEnvZ.addKey(pt[3], pt[2]); } else { k3 = strokeEnvZ.addKey(pt[3], 0); } k1.tension = 0.5; k2.tension = 0.5; k3.tension = 0.5; if (pCount !== 0) { var dx = pt[0] - lx; var dy = pt[1] - ly; var dz = pt[2] - lz; var dt = pt[3] - lt; var dlen = Math.sqrt(dx * dx + dy * dy + dz * dz); d += dlen; len_set[pCount-1] = dlen; time_set[pCount-1] = dt; } else { start_time = pt[3]; } lx = pt[0]; ly = pt[1]; lz = pt[2]; lt = pt[3]; } var dpos = start_time; var ptofs = obj.points.length; for (pCount = 0; pCount < len_set.length; pCount++) { var segLen = len_set[pCount]; var segTime = time_set[pCount]; var segNum = Math.ceil((segLen / divsper) * divs); for (var t = dpos, tMax = dpos + segTime, tInc = (segTime / segNum); t < (tMax - tInc); t += tInc) { if (t === dpos) { lx = strokeEnvX.evaluate(t); ly = strokeEnvY.evaluate(t); lz = strokeEnvZ.evaluate(t); } var px, py, pz; px = strokeEnvX.evaluate(t + tInc); py = strokeEnvY.evaluate(t + tInc); pz = strokeEnvZ.evaluate(t + tInc); var pdx = (px - lx), pdy = py - ly, pdz = pz - lz; var pd = Math.sqrt(pdx * pdx + pdy * pdy + pdz * pdz); var a; a = vec3.multiply( vec3.normalize( vec3.cross(this.viewvector, vec3.normalize([pdx, pdy, pdz]))), pwidth / 2.0); obj.addPoint([lx - a[0], -(ly - a[1]), (lz - a[2]) + (extrude ? (extrude_depth / 2.0) : 0)]); obj.addPoint([lx + a[0], -(ly + a[1]), (lz + a[2]) + (extrude ? (extrude_depth / 2.0) : 0)]); lx = px; ly = py; lz = pz; } dpos += segTime; } var ptlen = obj.points.length; if (extrude) { for (i = ptofs, iMax = ptlen; i < iMax; i++) { obj.addPoint([obj.points[i][0], obj.points[i][1], obj.points[i][2] - (extrude ? (extrude_depth / 2.0) : 0)]); } } for (i = 0, iMax = ptlen - ptofs; i <= iMax - 4; i += 2) { if (segCount % seg_mod === 0) { faceSegment++; } obj.setSegment(faceSegment); var arFace = [ptofs + i, ptofs + i + 1, ptofs + i + 3, ptofs + i + 2]; // var ftest = vec3.dot(this.viewvector, triangle.normal(obj.points[arFace[0]], obj.points[arFace[1]], obj.points[arFace[2]])); var faceNum = obj.addFace(arFace); // if (ftest < 0) { // this.faces[faceNum].flip(); // } if (extrude) { var arFace2 = [arFace[3] + ptlen - ptofs, arFace[2] + ptlen - ptofs, arFace[1] + ptlen - ptofs, arFace[0] + ptlen - ptofs]; faceNum = obj.addFace(arFace2); arFace2 = [ptofs + i, ptofs + i + 2, ptofs + i + 2 + ptlen - ptofs, ptofs + i + ptlen - ptofs]; faceNum = obj.addFace(arFace2); arFace2 = [ptofs + i + 1 + ptlen - ptofs, ptofs + i + 3 + ptlen - ptofs, ptofs + i + 3, ptofs + i + 1]; faceNum = obj.addFace(arFace2); if (i === 0) { arFace2 = [ptofs + i + ptlen - ptofs, ptofs + i + 1 + ptlen - ptofs, ptofs + i + 1, ptofs + i]; faceNum = obj.addFace(arFace2); } if (i === iMax - 4) { arFace2 = [ptofs + i + 2, ptofs + i + 3, ptofs + i + 3 + ptlen - ptofs, ptofs + i + 2 + ptlen - ptofs]; faceNum = obj.addFace(arFace2); } } segCount++; } } obj.calcFaceNormals(); obj.triangulateQuads(); obj.calcNormals(); obj.compile(); return obj; }; /* Particle System */ function Particle(pos, start_time, life_time, velocity, accel) { this.startpos = new Float32Array(pos); this.pos = new Float32Array(pos); this.velocity = new Float32Array((velocity !== undef) ? velocity : [0, 0, 0]); this.accel = new Float32Array((accel !== undef) ? accel : [0, 0, 0]); this.start_time = (start_time !== undef) ? start_time : 0; this.life_time = (life_time !== undef) ? life_time : 0; this.color = null; this.nextParticle = null; } function ParticleSystem(maxPts, hasColor, pTex, vWidth, vHeight, alpha, alphaCut) { var gl = GLCore.gl; if (!maxPts) { return; } this.particles = null; this.last_particle = null; this.pTex = (pTex !== undef) ? pTex : null; this.vWidth = vWidth; this.vHeight = vHeight; this.alpha = (alpha !== undef) ? alpha : false; this.alphaCut = (alphaCut !== undef) ? alphaCut : 0; this.pfunc = function(p, time) { var tdelta = time - p.start_time; if (tdelta < 0) { return 0; } if (tdelta > p.life_time && p.life_time) { return -1; } p.pos[0] = p.startpos[0] + (tdelta * p.velocity[0]) + (tdelta * tdelta * p.accel[0]); p.pos[1] = p.startpos[1] + (tdelta * p.velocity[1]) + (tdelta * tdelta * p.accel[1]); p.pos[2] = p.startpos[2] + (tdelta * p.velocity[2]) + (tdelta * tdelta * p.accel[2]); if (this.pgov !== null) { this.pgov(p, time); } return 1; }; this.pgov = null; if (hasColor === undef) { this.hasColor = false; } else { this.hasColor = hasColor; } // gl.enable(gl.VERTEX_PROGRAM_POINT_SIZE); var hasTex = (this.pTex !== null); this.vs = [ "#ifdef GL_ES", "precision highp float;", "#endif", "attribute vec3 aVertexPosition;", this.hasColor ? "attribute vec3 aColor;" : "", "uniform mat4 uMVMatrix;", "uniform mat4 uPMatrix;", "varying vec4 color;", "varying vec2 screenPos;", hasTex ? "varying float pSize;" : "", "void main(void) {", "vec4 position = uPMatrix * uMVMatrix * vec4(aVertexPosition,1.0);", hasTex ? "screenPos=vec2(position.x/position.w,position.y/position.w);" : "", "gl_Position = position;", this.hasColor ? "color = vec4(aColor.r,aColor.g,aColor.b,1.0);" : "color = vec4(1.0,1.0,1.0,1.0);", hasTex ? "pSize=200.0/position.z;" : "float pSize=200.0/position.z;", "gl_PointSize = pSize;", "}"].join("\n"); this.fs = [ "#ifdef GL_ES", "precision highp float;", "#endif", hasTex ? "uniform sampler2D pMap;" : "", "varying vec4 color;", hasTex ? "varying vec2 screenPos;" : "", hasTex ? "uniform vec3 screenDim;" : "", hasTex ? "varying float pSize;" : "", "void main(void) {", "vec4 c = color;", hasTex ? "vec2 screen=vec2((gl_FragCoord.x/screenDim.x-0.5)*2.0,(gl_FragCoord.y/screenDim.y-0.5)*2.0);" : "", hasTex ? "vec2 pointCoord=vec2( ((screen.x-screenPos.x)/(pSize/screenDim.x))/2.0+0.5,((screen.y-screenPos.y)/(pSize/screenDim.y))/2.0+0.5);" : "", hasTex ? "vec4 tc = texture2D(pMap,pointCoord); gl_FragColor = vec4(c.rgb*tc.rgb,1.0);" : "gl_FragColor = c;", "}"].join("\n"); this.maxPoints = maxPts; this.numParticles = 0; this.arPoints = new Float32Array(maxPts * 3); this.glPoints = null; if (hasColor) { this.arColor = new Float32Array(maxPts * 3); this.glColor = null; } this.shader_particle = new Shader(this.vs, this.fs); this.shader_particle.use(); this.shader_particle.addVertexArray("aVertexPosition"); if (this.hasColor) { this.shader_particle.addVertexArray("aColor"); } this.shader_particle.addMatrix("uMVMatrix"); this.shader_particle.addMatrix("uPMatrix"); if (this.pTex !== null) { this.shader_particle.addInt("pMap", 0); this.shader_particle.addVector("screenDim"); this.shader_particle.setVector("screenDim", [vWidth, vHeight, 0]); } this.genBuffer(); } ParticleSystem.prototype.resizeView = function(vWidth, vHeight) { this.vWidth = vWidth; this.vHeight = vHeight; if (this.pTex !== null) { this.shader_particle.addVector("screenDim"); this.shader_particle.setVector("screenDim", [vWidth, vHeight, 0]); } }; ParticleSystem.prototype.addParticle = function(p) { if (this.last_particle === null) { this.particles = p; this.last_particle = p; } else { this.last_particle.nextParticle = p; this.last_particle = p; } }; ParticleSystem.prototype.genBuffer = function() { var gl = GLCore.gl; this.glPoints = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.glPoints); gl.bufferData(gl.ARRAY_BUFFER, this.arPoints, gl.DYNAMIC_DRAW); if (this.hasColor) { this.glColor = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.glColor); gl.bufferData(gl.ARRAY_BUFFER, this.arColor, gl.DYNAMIC_DRAW); } }; ParticleSystem.prototype.updatePoints = function() { var gl = GLCore.gl; // buffer update gl.bindBuffer(gl.ARRAY_BUFFER, this.glPoints); gl.bufferData(gl.ARRAY_BUFFER, this.arPoints, gl.DYNAMIC_DRAW); // end buffer update }; ParticleSystem.prototype.updateColors = function() { var gl = GLCore.gl; if (!this.hasColor) { return; } // buffer update gl.bindBuffer(gl.ARRAY_BUFFER, this.glColor); gl.bufferData(gl.ARRAY_BUFFER, this.arColor, gl.DYNAMIC_DRAW); // end buffer update }; ParticleSystem.prototype.draw = function(modelViewMat, projectionMat, time) { var gl = GLCore.gl; this.shader_particle.use(); if (this.pTex !== null) { this.pTex.use(gl.TEXTURE0); } this.shader_particle.setMatrix("uMVMatrix", modelViewMat); this.shader_particle.setMatrix("uPMatrix", projectionMat); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindBuffer(gl.ARRAY_BUFFER, this.glPoints); gl.vertexAttribPointer(this.shader_particle.uniforms["aVertexPosition"], 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(this.shader_particle.uniforms["aVertexPosition"]); if (this.hasColor) { gl.bindBuffer(gl.ARRAY_BUFFER, this.glColor); gl.vertexAttribPointer(this.shader_particle.uniforms["aColor"], 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(this.shader_particle.uniforms["aColor"]); } if (time === undef) { time = 0; } if (this.particles === null) { gl.disable(gl.BLEND); return; } var p = this.particles; var lp = null; this.numParticles = 0; var c = 0; while (p !== null) { var ofs = this.numParticles * 3; var pf = this.pfunc(p, time); if (pf === 1) { this.arPoints[ofs] = p.pos[0]; this.arPoints[ofs + 1] = p.pos[1]; this.arPoints[ofs + 2] = p.pos[2]; if (p.color !== null && this.arColor !== undef) { this.arColor[ofs] = p.color[0]; this.arColor[ofs + 1] = p.color[1]; this.arColor[ofs + 2] = p.color[2]; } this.numParticles++; c++; if (this.numParticles === this.maxPoints) { break; } } else if (pf === -1) // particle death { if (lp !== null) { lp.nextParticle = p.nextParticle; } } else if (pf === 0) { c++; } lp = p; p = p.nextParticle; } if (!c) { this.particles = null; this.last_particle = null; } this.updatePoints(); if (this.hasColor) { this.updateColors(); } if (this.alpha) { gl.enable(gl.BLEND); gl.enable(gl.DEPTH_TEST); gl.depthMask(0); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR); } gl.drawArrays(gl.POINTS, 0, this.numParticles); if (this.alpha) { // gl.enable(gl.DEPTH_TEST); gl.disable(gl.BLEND); gl.depthMask(1); gl.blendFunc(gl.ONE, gl.ONE); } if (this.hasColor) { gl.disableVertexAttribArray(this.shader_particle.uniforms["aColor"]); } }; /* SkyBox */ function SkyBox(in_obj) { var texture = in_obj.texture; var mapping = in_obj.mapping; var that = this; this.mapping = null; this.ready = false; this.texture = null; this.onready = function() { texture.onready = null; var tw = 1/Images[that.texture.tex_id].width; var th = 1/Images[that.texture.tex_id].height; if (that.mapping === null) { that.mapping = [[1/3, 0.5, 2/3-tw, 1],//top [0, 0.5, 1/3, 1], //bottom [0, 0, 1/3-tw, 0.5], //left [2/3, 0, 1, 0.5], //right [2/3+tw, 0.5, 1, 1], //front [1/3, 0, 2/3, 0.5]]; //back } //if var mat = new Material("skybox"); var obj = new Mesh(); obj.sky_mapping = that.mapping; cubicvr_boxObject(obj, 1, mat); obj.calcNormals(); var mat_map = new UVMapper(); mat_map.projection_mode = enums.uv.projection.SKY; mat_map.scale = [1, 1, 1]; mat_map.apply(obj, mat); obj.triangulateQuads(); obj.compile(); mat.setTexture(texture); that.scene_object = new SceneObject(obj); that.ready = true; } //onready if (texture) { if (typeof(texture) === "string") { texture = new Texture(texture, null, null, null, this.onready); } else if (!texture.loaded){ texture.onready = this.onready; } //if this.texture = texture; if (mapping) { this.mapping = mapping; this.onready(); } //if } //if } //cubicvr_SkyBox::Constructor function View(obj_init) { this.texture = obj_init.texture?obj_init.texture:null; this.width = obj_init.width?obj_init.width:128; this.height = obj_init.height?obj_init.height:128; this.x = obj_init.x?obj_init.x:0; this.y = obj_init.y?obj_init.y:0; this.blend = obj_init.blend?obj_init.blend:false; this.opacity = (typeof(obj_init.opacity)!=='undefined')?obj_init.opacity:1.0; this.tint = obj_init.tint?obj_init.tint:[1.0,1.0,1.0]; this.type='view'; this.superView = null; this.childViews = []; this.panel = null; } View.prototype.addSubview = function(view) { this.childViews.push(view); // this.superView.makePanel(view); view.superView = this; } View.prototype.makePanel = function(view) { return this.superView.makePanel(view); } function Layout(obj_init) { this.texture = obj_init.texture?obj_init.texture:null; this.width = obj_init.width?obj_init.width:128; this.height = obj_init.height?obj_init.height:128; this.x = obj_init.x?obj_init.x:0; this.y = obj_init.y?obj_init.y:0; this.blend = obj_init.blend?obj_init.blend:false; this.opacity = (typeof(obj_init.opacity)!=='undefined')?obj_init.opacity:1.0; this.tint = obj_init.tint?obj_init.tint:[1.0,1.0,1.0]; this.type = 'root'; this.superView = null; this.childViews = []; this.setupShader(); this.panel = null; this.makePanel(this); } Layout.prototype.setupShader = function() { this.shader = new CubicVR.PostProcessShader({ shader_vertex: ["attribute vec3 aVertex;", "attribute vec2 aTex;", "varying vec2 vTex;", "uniform vec3 screen;", "uniform vec3 position;", "uniform vec3 size;", "void main(void) {", "vTex = aTex;", "vec4 vPos = vec4(aVertex.xyz,1.0);", "vPos.x *= size.x/screen.x;", "vPos.y *= size.y/screen.y;", "vPos.x += (size.x/screen.x);", "vPos.y -= (size.y/screen.y);", "vPos.x += (position.x/screen.x)*2.0 - 1.0;", "vPos.y -= (position.y/screen.y)*2.0 - 1.0;", "gl_Position = vPos;", "}"].join("\n"), shader_fragment: [ "#ifdef GL_ES", "precision highp float;", "#endif", "uniform sampler2D srcTex;", "uniform vec3 tint;", "varying vec2 vTex;", "void main(void) {", "vec4 color = texture2D(srcTex, vTex)*vec4(tint,1.0);", "if (color.a == 0.0) discard;", "gl_FragColor = color;", "}"].join("\n"), init: function(shader) { shader.setInt("srcTex",0); shader.addVector("screen"); shader.addVector("position"); shader.addVector("tint"); shader.addVector("size"); } }); } Layout.prototype.addSubview = function(view) { this.childViews.push(view); // this.makePanel(view); view.superView = this; } Layout.prototype.makePanel = function(view) { var gl = CubicVR.GLCore.gl; var pQuad = {}; // intentional empty object pQuad.vbo_points = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0]); pQuad.vbo_uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1]); pQuad.gl_points = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, pQuad.gl_points); gl.bufferData(gl.ARRAY_BUFFER, pQuad.vbo_points, gl.STATIC_DRAW); pQuad.gl_uvs = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, pQuad.gl_uvs); gl.bufferData(gl.ARRAY_BUFFER, pQuad.vbo_uvs, gl.STATIC_DRAW); view.panel = pQuad; } Layout.prototype.renderPanel = function(view,panel) { var gl = CubicVR.GLCore.gl; if (!view.texture) { return false; } view.texture.use(gl.TEXTURE0); }; Layout.prototype.renderView = function(view) { if (!view.texture) return; var gl = CubicVR.GLCore.gl; var offsetLeft = view.offsetLeft; var offsetTop = view.offsetTop; if (!offsetLeft) offsetLeft = 0; if (!offsetTop) offsetTop = 0; var shader = this.shader.shader; shader.use(); shader.setVector("screen",[this.width,this.height,0]); shader.setVector("position",[view.x+offsetLeft,view.y+offsetTop,0]); shader.setVector("size",[view.width,view.height,0]); shader.setVector("tint",view.tint); if (view.blend) { gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); } view.texture.use(gl.TEXTURE0); // this.renderPanel(view,this.panel); gl.drawArrays(gl.TRIANGLES, 0, 6); if (view.blend) { gl.disable(gl.BLEND); gl.blendFunc(gl.ONE,gl.ZERO); } } Layout.prototype.render = function() { var gl = CubicVR.GLCore.gl; gl.disable(gl.DEPTH_TEST); if (this.texture) this.renderView(this); var stack = []; var framestack = []; this.offsetLeft = 0, this.offsetTop = 0; stack.push(this); shader = this.shader.shader; shader.use(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); gl.bindBuffer(gl.ARRAY_BUFFER, this.panel.gl_points); gl.vertexAttribPointer(shader.uniforms["aVertex"], 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(shader.uniforms["aVertex"]); gl.bindBuffer(gl.ARRAY_BUFFER, this.panel.gl_uvs); gl.vertexAttribPointer(shader.uniforms["aTex"], 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(shader.uniforms["aTex"]); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); while (stack.length) { var view = stack.pop(); this.renderView(view); if (view.childViews.length) { for (var i = view.childViews.length-1, iMin = 0; i >= iMin; i--) { view.childViews[i].offsetLeft = view.x+view.offsetLeft; view.childViews[i].offsetTop = view.y+view.offsetTop; stack.push(view.childViews[i]); } } } gl.disableVertexAttribArray(shader.uniforms["aTex"]); gl.enable(gl.DEPTH_TEST); } // Full-screen quad related var fsQuad = { make:makeFSQuad, destroy:destroyFSQuad, render:renderFSQuad }; // Extend CubicVR module by adding public methods and classes var extend = { init: GLCore.init, enums: enums, vec2: vec2, vec3: vec3, mat4: mat4, util: util, fsQuad: fsQuad, IdentityMatrix: cubicvr_identity, GLCore: GLCore, Timer: Timer, MainLoop: MainLoop, MouseViewController: MouseViewController, setMainLoop: setMainLoop, Transform: Transform, Light: Light, Texture: Texture, PJSTexture: PJSTexture, CanvasTexture: CanvasTexture, TextTexture: TextTexture, UVMapper: UVMapper, Scene: Scene, SceneObject: SceneObject, Face: Face, Material: Material, Materials: Materials, Textures: Textures, Textures_obj: Textures_obj, Images: Images, Shader: Shader, Landscape: Landscape, Camera: Camera, GML: GML, SkyBox: SkyBox, Envelope: Envelope, Motion: Motion, RenderBuffer: RenderBuffer, PostProcessFX: PostProcessFX, PostProcessChain: PostProcessChain, PostProcessShader: PostProcessShader, NormalMapGen: NormalMapGen, Particle: Particle, ParticleSystem: ParticleSystem, Octree: Octree, OctreeWorker: OctreeWorkerProxy, Quaternion: Quaternion, AutoCamera: AutoCamera, Mesh: Mesh, MeshPool: MeshPool, genPlaneObject: cubicvr_planeObject, genBoxObject: cubicvr_boxObject, genLatheObject: cubicvr_latheObject, genTorusObject: cubicvr_torusObject, genConeObject: cubicvr_coneObject, genCylinderObject: cubicvr_cylinderObject, genSphereObject: cubicvr_sphereObject, primitives: primitives, renderObject: cubicvr_renderObject, globalAmbient: [0.1, 0.1, 0.1], setGlobalAmbient: function(c) { CubicVR.globalAmbient = c; }, loadMesh: cubicvr_loadMesh, DeferredBin: DeferredBin, DeferredLoadTexture: DeferredLoadTexture, loadCollada: cubicvr_loadCollada, loadColladaWorker: cubicvr_loadColladaWorker, setGlobalDepthAlpha: GLCore.setDepthAlpha, setDefaultFilter: GLCore.setDefaultFilter, Worker: CubicVR_Worker, Layout: Layout, View: View }; for (var ext in extend) { if (extend.hasOwnProperty(ext)) { this.CubicVR[ext] = extend[ext]; } } Materials.push(new Material("(null)")); }());