aboutsummaryrefslogtreecommitdiff
path: root/demos/webgl/CubicVR.js
diff options
context:
space:
mode:
Diffstat (limited to 'demos/webgl/CubicVR.js')
-rw-r--r--demos/webgl/CubicVR.js11660
1 files changed, 11660 insertions, 0 deletions
diff --git a/demos/webgl/CubicVR.js b/demos/webgl/CubicVR.js
new file mode 100644
index 00000000..897fc887
--- /dev/null
+++ b/demos/webgl/CubicVR.js
@@ -0,0 +1,11660 @@
+/*
+ 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<chain.length; ++i) {
+ fn = fn[chain[i]];
+ } //for
+ if (fn && typeof fn === 'function') {
+ var ret = fn.apply(fn, args);
+ postMessage(ret);
+ } //if
+ }
+ else {
+ throw new Error('Worker command not formatted properly.');
+ } //if
+ }
+ else if (message === "data") {
+ if (WorkerConnection.listener !== null) {
+ var data = e.data ? e.data.data : null;
+ WorkerConnection.listener.onmessage(e.data.data);
+ } //if
+ }
+ else if (message === "stop") {
+ if (WorkerConnection.listener !== null && WorkerConnection.listener.stop) {
+ WorkerConnection.listener.stop();
+ } //if
+ } //if
+ }, false);
+ } //if
+
+ /* Timer */
+
+ function Timer() {
+ this.time_elapsed = 0;
+ this.system_milliseconds = 0;
+ this.start_time = 0;
+ this.end_time = 0;
+ this.last_update = 0;
+ this.paused_time = 0;
+ this.offset = 0;
+ this.paused_state = 0;
+ }
+
+
+ Timer.prototype.start = function () {
+ this.update();
+ this.num_updates = 0;
+ this.start_time = this.system_milliseconds;
+ this.last_update = this.start_time;
+ this.paused_state = false;
+ this.lock_state = false;
+ this.lock_rate = 0;
+ this.paused_time = 0;
+ this.offset = 0;
+ }
+
+
+ Timer.prototype.stop = function () {
+ this.end_time = this.system_milliseconds;
+ }
+
+
+ Timer.prototype.reset = function () {
+ this.start();
+ }
+
+
+ Timer.prototype.lockFramerate = function (f_rate) {
+ this.lock_rate = 1.0 / this.f_rate;
+ this.lock_state = true;
+ }
+
+
+ Timer.prototype.unlock = function () {
+ var msec_tmp = this.system_milliseconds;
+ this.lock_state = false;
+ this.update();
+ this.last_update = this.system_milliseconds - this.lock_rate;
+ this.offset += msec_tmp - this.system_milliseconds;
+ this.lock_rate = 0;
+ }
+
+ Timer.prototype.locked = function () {
+ return this.lock_state;
+ }
+
+ Timer.prototype.update = function () {
+ this.num_updates++;
+ this.last_update = this.system_milliseconds;
+
+ if (this.lock_state) {
+ this.system_milliseconds += parseInt(lock_rate * 1000);
+ } else {
+ this.system_milliseconds = (new Date()).getTime();
+ }
+
+
+ if (this.paused_state) this.paused_time += this.system_milliseconds - this.last_update;
+
+ this.time_elapsed = this.system_milliseconds - this.start_time - this.paused_time + this.offset;
+ }
+
+
+ Timer.prototype.getMilliseconds = function () {
+ return this.time_elapsed;
+ }
+
+
+
+ Timer.prototype.getSeconds = function () {
+ return this.getMilliseconds() / 1000.0;
+ }
+
+
+ Timer.prototype.setMilliseconds = function (milliseconds_in) {
+ this.offset -= (this.system_milliseconds - this.start_time - this.paused_time + this.offset) - milliseconds_in;
+ }
+
+
+
+ Timer.prototype.setSeconds = function (seconds_in) {
+ this.setMilliseconds(parseInt(seconds_in * 1000.0));
+ }
+
+
+ Timer.prototype.getLastUpdateSeconds = function () {
+ return this.getLastUpdateMilliseconds() / 1000.0;
+ }
+
+
+ Timer.prototype.getLastUpdateMilliseconds = function () {
+ return this.system_milliseconds - this.last_update;
+ }
+
+ Timer.prototype.getTotalMilliseconds = function () {
+ return this.system_milliseconds - this.start_time;
+ }
+
+
+ Timer.prototype.getTotalSeconds = function () {
+ return this.getTotalMilliseconds() / 1000.0;
+ }
+
+
+ Timer.prototype.getNumUpdates = function () {
+ return this.num_updates;
+ }
+
+
+ Timer.prototype.setPaused = function (pause_in) {
+ this.paused_state = pause_in;
+ }
+
+ Timer.prototype.getPaused = function () {
+ return this.paused_state;
+ }
+
+
+ /* Run-Loop Controller */
+
+ function MainLoopRequest()
+ {
+ var gl = GLCore.gl;
+
+ if (CubicVR.GLCore.mainloop === null) return;
+
+ CubicVR.GLCore.mainloop.interval();
+
+ if (window.requestAnimationFrame) {
+ window.requestAnimationFrame(MainLoopRequest);
+ }
+ }
+
+ function setMainLoop(ml)
+ {
+ CubicVR.GLCore.mainloop=ml;
+ }
+
+ function MainLoop(mlfunc,doclear)
+ {
+ if (window.requestAnimationFrame === undef) {
+ window.requestAnimationFrame = null; // XXX Emscripten - Disable this for now, due to bugginess window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || null;
+ }
+
+ if (CubicVR.GLCore.mainloop !== null)
+ {
+ // kill old mainloop
+
+ if (!(window.requestAnimationFrame) && CubicVR.GLCore.mainloop)
+ {
+ clearInterval(CubicVR.GLCore.mainloop.interval);
+ }
+
+ CubicVR.GLCore.mainloop = null;
+ }
+
+ if (mlfunc === null)
+ {
+ CubicVR.GLCore.mainloop = null;
+ return;
+ }
+
+ var timer = new Timer();
+ timer.start();
+
+ this.timer = timer;
+ this.func = mlfunc;
+ this.doclear = (doclear!==undef)?doclear:true;
+ CubicVR.GLCore.mainloop = this;
+
+ var loopFunc = function() { return function() {
+ var gl = CubicVR.GLCore.gl;
+ timer.update();
+ if (CubicVR.GLCore.mainloop.doclear) gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ mlfunc(timer,CubicVR.GLCore.gl);
+ }; }();
+
+ if (window.requestAnimationFrame) {
+ loopFunc();
+ this.interval = loopFunc;
+ window.requestAnimationFrame(MainLoopRequest);
+ } else {
+ this.interval = setInterval(loopFunc, 1000/60); // XXX Emscripten: Need 1/60 for bullet, not the usual 1/50
+ }
+ }
+
+ MainLoop.prototype.setPaused = function(state) {
+ this.timer.setPaused(state);
+ };
+
+ MainLoop.prototype.getPaused = function() {
+ return this.timer.getPaused();
+ };
+
+ MainLoop.prototype.setTimerSeconds = function(time_in) {
+ this.timer.setSeconds(time_in);
+ };
+
+
+ MainLoop.prototype.getTimerSeconds = function() {
+ return this.timer.getSeconds();
+ };
+
+
+ MainLoop.prototype.resetTimer = function() {
+ this.timer.reset();
+ };
+
+
+ /* Simple Orbital View Controller */
+ function MouseViewController(canvas,cam_in)
+ {
+ this.canvas = canvas;
+ this.camera = cam_in;
+ this.mpos = [0,0]
+ this.mdown = false;
+
+ var ctx = this;
+
+ this.onMouseDown = function () { return function (ev)
+ {
+ ctx.mdown = true;
+ ctx.mpos = [ev.pageX-ev.target.offsetLeft,ev.pageY-ev.target.offsetTop];
+ } }();
+
+ this.onMouseUp = function () { return function (ev)
+ {
+ ctx.mdown = false;
+ ctx.mpos = [ev.pageX-ev.target.offsetLeft,ev.pageY-ev.target.offsetTop];
+ } }();
+
+ this.onMouseMove = function () { return function (ev)
+ {
+ var mdelta = [];
+
+ var npos = [ev.pageX-ev.target.offsetLeft,ev.pageY-ev.target.offsetTop];
+
+ mdelta[0] = ctx.mpos[0]-npos[0];
+ mdelta[1] = ctx.mpos[1]-npos[1];
+
+ ctx.mpos = npos;
+// ctx.mpos = [ev.clientX,ev.clientY];
+ if (!ctx.mdown) return;
+
+ var dv = vec3.subtract(ctx.camera.target,ctx.camera.position);
+ var dist = vec3.length(dv);
+
+ ctx.camera.position = vec3.moveViewRelative(ctx.camera.position,ctx.camera.target,dist*mdelta[0]/300.0,0);
+ ctx.camera.position[1] -= dist*mdelta[1]/300.0;
+
+ ctx.camera.position = vec3.add(ctx.camera.target,vec3.multiply(vec3.normalize(vec3.subtract(ctx.camera.position,ctx.camera.target)),dist));
+ } }();
+
+ this.onMouseWheel = function() { return function (ev)
+ {
+ var delta = ev.wheelDelta?ev.wheelDelta:(-ev.detail*10.0);
+
+ var dv = vec3.subtract(ctx.camera.target,ctx.camera.position);
+ var dist = vec3.length(dv);
+
+ dist -= delta/1000.0;
+
+ if (dist < 0.1) dist = 0.1;
+ if (dist > 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<lines; ++i) {
+ var w = ctx.measureText(text[i]).width;
+ if (w > 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<lines; ++i) {
+ var x = (options && options.x) || align === 'center' ? canvas.width/2 : align === 'right' ? canvas.width : 0;
+ ctx.fillText(text[i], x, y+i*lineHeight);
+ } //for
+ } //if
+ ctx.fill();
+
+ this.use = CanvasTexture.prototype.use;
+ this.clear = CanvasTexture.prototype.clear;
+ this.update = CanvasTexture.prototype.update;
+ CanvasTexture.apply(this, [canvas]);
+
+ this.update();
+ this.canvasSource = canvas = ctx = null;
+}; //TextTexture
+
+function PJSTexture(pjsURL, width, height) {
+ var gl = CubicVR.GLCore.gl;
+ this.texture = new CubicVR.Texture();
+ this.canvas = document.createElement("CANVAS");
+ this.canvas.width = width;
+ this.canvas.height = height;
+
+ // this assumes processing is already included..
+ this.pjs = new Processing(this.canvas,CubicVR.util.getURL(pjsURL));
+ this.pjs.noLoop();
+ this.pjs.redraw();
+
+ var tw = this.canvas.width, th = this.canvas.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; }
+ }
+
+ // 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<li; ++i) {
+ var light = this._static_lights[i];
+ light.octree_leaves = null;
+ light.octree_common_root = null;
+ light.octree_aabb = null;
+ } //for
+ for (var i=0, li = this._lights.length; i<li; ++i) {
+ var light = this._lights[i];
+ light.octree_leaves = null;
+ light.octree_common_root = null;
+ light.octree_aabb = null;
+ } //for
+ this._static_lights = null;
+ this._lights = null;
+ for (var i = 0, len = this._children.length; i < len; ++i) {
+ if (this._children[i] !== null) {
+ this._children[i].destroy();
+ } //if
+ } //for
+ for (var i = 0, max_i = this._nodes.length; i < max_i; ++i) {
+ var node = this._nodes[i];
+ node.octree_leaves = null;
+ node.octree_common_root = null;
+ node.octree_aabb = null;
+ node.dynamic_lights = [];
+ node.static_lights = [];
+ } //for
+ 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;
+ this._children = null;
+ this._root = null;
+ this._position = null;
+ this._nodes = null;
+ this._lights = null;
+ this._static_lights = null;
+ this._sphere = null;
+ this._bbox = null;
+} //Octree::destroy
+Octree.prototype.toString = function() {
+ var real_size = [this._bbox[1][0] - this._bbox[0][0], this._bbox[1][2] - this._bbox[0][2]];
+ return "[Octree: @" + this._position + ", depth: " + this._max_depth + ", size: " + this._size + ", nodes: " + this._nodes.length + ", measured size:" + real_size + "]";
+}; //Octree::toString
+Octree.prototype.remove = function(node) {
+ var dont_check_lights = false;
+ var len = this._nodes.length;
+ var i;
+ for (i = len - 1, len = this._nodes.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<li; ++i) {
+ if (node.static_lights.indexOf(this._static_lights[i]) === -1) {
+ node.static_lights.push(this._static_lights[i]);
+ } //if
+ } //for
+ for (var i = 0; i < 8; ++i) {
+ if (this._children[i] !== null) {
+ this._children[i].collect_static_lights(node);
+ } //if
+ } //for
+}; //collect_static_lights
+Octree.prototype.insert = function(node, is_light) {
+ if (is_light === undef) { is_light = false; }
+ function $insert(octree, node, is_light, root) {
+ var i, li;
+ if (is_light) {
+ if (node.method === enums.light.method.STATIC) {
+ if (octree._static_lights.indexOf(node) === -1) {
+ octree._static_lights.push(node);
+ } //if
+ for (i=0; i<octree._nodes.length; ++i) {
+ if (octree._nodes[i].static_lights.indexOf(node) === -1) {
+ octree._nodes[i].static_lights.push(node);
+ } //if
+ } //for
+ var root_tree = octree._root;
+ while (root_tree !== null) {
+ for (var i=0, l=root_tree._nodes.length; i<l; ++i) {
+ var n = root_tree._nodes[i];
+ if (n.static_lights.indexOf(node) === -1) {
+ n.static_lights.push(node);
+ } //if
+ } //for
+ root_tree = root_tree._root;
+ } //while
+ }
+ else {
+ if (octree._lights.indexOf(node) === -1) {
+ octree._lights.push(node);
+ } //if
+ } //if
+ } else {
+ octree._nodes.push(node);
+ for (i=0, li = octree._static_lights.length; i<li; ++i) {
+ if (node.static_lights.indexOf(octree._static_lights[i]) === -1) {
+ node.static_lights.push(octree._static_lights[i]);
+ } //if
+ } //for
+ var root_tree = octree._root;
+ while (root_tree !== null) {
+ for (var i=0, l=root_tree._static_lights.length; i<l; ++i) {
+ var light = root_tree._static_lights[i];
+ if (node.static_lights.indexOf(light) === -1) {
+ node.static_lights.push(light);
+ } //if
+ } //for
+ root_tree = root_tree._root;
+ } //while
+ } //if
+ node.octree_leaves.push(octree);
+ node.octree_common_root = root;
+ AABB_engulf(node.octree_aabb, octree._bbox[0]);
+ AABB_engulf(node.octree_aabb, octree._bbox[1]);
+ } //$insert
+ if (this._root === null) {
+ node.octree_leaves = [];
+ node.octree_common_root = null;
+ } //if
+ if (this._max_depth === 0) {
+ $insert(this, node, is_light, this._root);
+ return;
+ } //if
+ //Check to see where the node is
+ var p = this._position;
+ var t_nw, t_ne, t_sw, t_se, b_nw, b_ne, b_sw, b_se;
+ var aabb = node.getAABB();
+ var min = [aabb[0][0], aabb[0][1], aabb[0][2]];
+ var max = [aabb[1][0], aabb[1][1], aabb[1][2]];
+
+ t_nw = min[0] < p[0] && min[1] < p[1] && min[2] < p[2];
+ t_ne = max[0] > 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<ii; ++i) {
+ if (node.static_lights === undef) node.static_lights = [];
+ if (node.static_lights.indexOf(this._static_lights[i]) === -1) {
+ node.static_lights.push(this._static_lights[i]);
+ } //if
+ } //for
+
+ var new_size = this._size / 2;
+ var offset = this._size / 4;
+ var new_position;
+
+ var num_inserted = 0;
+ //Create & check children to see if node fits there too
+ var x = this._position[0];
+ var y = this._position[1];
+ var z = this._position[2];
+ if (t_nw) {
+ new_position = [x - offset, y - offset, z - offset];
+ if (this._children[enums.octree.TOP_NW] === null) {
+ this._children[enums.octree.TOP_NW] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.TOP_NW);
+ }
+ this._children[enums.octree.TOP_NW].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (t_ne) {
+ new_position = [x + offset, y - offset, z - offset];
+ if (this._children[enums.octree.TOP_NE] === null) {
+ this._children[enums.octree.TOP_NE] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.TOP_NE);
+ }
+ this._children[enums.octree.TOP_NE].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (b_nw) {
+ new_position = [x - offset, y + offset, z - offset];
+ if (this._children[enums.octree.BOTTOM_NW] === null) {
+ this._children[enums.octree.BOTTOM_NW] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.BOTTOM_NW);
+ }
+ this._children[enums.octree.BOTTOM_NW].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (b_ne) {
+ new_position = [x + offset, y + offset, z - offset];
+ if (this._children[enums.octree.BOTTOM_NE] === null) {
+ this._children[enums.octree.BOTTOM_NE] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.BOTTOM_NE);
+ }
+ this._children[enums.octree.BOTTOM_NE].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (t_sw) {
+ new_position = [x - offset, y - offset, z + offset];
+ if (this._children[enums.octree.TOP_SW] === null) {
+ this._children[enums.octree.TOP_SW] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.TOP_SW);
+ }
+ this._children[enums.octree.TOP_SW].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (t_se) {
+ new_position = [x + offset, y - offset, z + offset];
+ if (this._children[enums.octree.TOP_SE] === null) {
+ this._children[enums.octree.TOP_SE] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.TOP_SE);
+ }
+ this._children[enums.octree.TOP_SE].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (b_sw) {
+ new_position = [x - offset, y + offset, z + offset];
+ if (this._children[enums.octree.BOTTOM_SW] === null) {
+ this._children[enums.octree.BOTTOM_SW] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.BOTTOM_SW);
+ }
+ this._children[enums.octree.BOTTOM_SW].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (b_se) {
+ new_position = [x + offset, y + offset, z + offset];
+ if (this._children[enums.octree.BOTTOM_SE] === null) {
+ this._children[enums.octree.BOTTOM_SE] = new Octree(new_size, this._max_depth - 1, this, new_position, enums.octree.BOTTOM_SE);
+ }
+ this._children[enums.octree.BOTTOM_SE].insert(node, is_light);
+ ++num_inserted;
+ } //if
+ if (num_inserted > 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<l;++i) {
+ var n = nodes[i];
+ if (n.name == target) {
+ map_context.strokeStyle = "#FFFF00";
+ map_context.lineWidth = 3;
+ 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.closePath();
+ map_context.stroke();
+
+ var oab = n.octree_aabb;
+ map_context.strokeStyle = "#0000FF";
+ $draw_box(oab[0][0], oab[0][2], oab[1][0], oab[1][2]);
+ map_context.lineWidth = 1;
+ if (n.common_root !== null) {
+ map_context.strokeStyle = "#00FF00";
+ //$draw_oct(n.octree_common_root);
+ } //if
+ break;
+ } //if
+ } //for
+ map_context.lineWidth = 1;
+ map_context.strokeStyle = "#FFFF00";
+ $draw_oct(this, "#444444");
+ map_context.fill();
+ map_context.restore();
+
+ } //if
+
+ for (i = 0, len = this._children.length; i < len; ++i) {
+ if (this._children[i] !== null) {
+ this._children[i].draw_on_map(map_canvas, map_context, target);
+ }
+ } //for
+}; //Octree::draw_on_map
+Octree.prototype.contains_point = function(position) {
+ return position[0] <= this._position[0] + this._size / 2 && position[1] <= this._position[1] + this._size / 2 && position[2] <= this._position[2] + this._size / 2 && position[0] >= 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<lj; ++j) {
+ if(obj_lights.indexOf(this._lights[j]) < 0) {
+ obj_lights.push(this._lights[j]);
+ } //if
+ } //for j
+ } //for o
+ //hits.lights = hits.lights.concat(child_hits.lights);
+ //collect lights and make sure they're unique <- really slow
+ for (o = 0, max_o = child_hits.lights.length; o < max_o; ++o) {
+ if (hits.lights.indexOf(child_hits.lights[o]) < 0) {
+ hits.lights.push(child_hits.lights[o]);
+ } //if
+ } //for o
+ } //if
+ } //for
+ return hits;
+}; //Octree::get_frustum_hits
+Octree.prototype.reset_node_visibility = function() {
+ this._debug_visible = false;
+
+ var i, l;
+ for (i = 0, l = this._nodes.length; i < l; ++i) {
+ this._nodes[i].culled = true;
+ } //for
+ for (i = 0, l = this._lights.length; i < l; ++i) {
+ this._lights[i].culled = true;
+ } //for
+ for (i = 0, l = this._static_lights.length; i < l; ++i) {
+ this._static_lights[i].culled = true;
+ } //for
+ for (i = 0, l = this._children.length; i < l; ++i) {
+ if (this._children[i] !== null) {
+ this._children[i].reset_node_visibility();
+ } //if
+ } //for
+}; //Octree::reset_visibility
+/***********************************************
+ * OctreeNode
+ ***********************************************/
+
+function OctreeNode() {
+ this.position = [0, 0, 0];
+ this.visible = false;
+ this._object = null;
+} //OctreeNode::Constructor
+OctreeNode.prototype.toString = function() {
+ return "[OctreeNode " + this.position + "]";
+}; //OctreeNode::toString
+OctreeNode.prototype.attach = function(obj) {
+ this._object = obj;
+}; //OctreeNode::attach
+
+function CubicVR_OctreeWorker() {
+ this.octree = null;
+ this.nodes = [];
+ this.camera = null;
+} //CubicVR_OctreeWorker::Constructor
+CubicVR_OctreeWorker.prototype.onmessage = function(input) {
+ var message = input.message;
+ if (message === "init") {
+ var params = input.data;
+ this.octree = new Octree(params.size, params.max_depth);
+ this.camera = new Camera();
+ }
+ else if (type === "set_camera") {
+ var data = message.data;
+ this.camera.mvMatrix = data.mvMatrix;
+ this.camera.pMatrix = data.pMatrix;
+ this.camera.position = data.position;
+ this.camera.target = data.target;
+ this.camera.frustum.extract(this.camera, this.camera.mvMatrix, this.camera.pMatrix);
+ }
+ else if (type === "insert") {
+ var json_node = JSON.parse(message.data);
+ var node = new SceneObject();
+ var trans = new Transform();
+
+ for (var i in json_node) {
+ if (json_node.hasOwnProperty(i)) {
+ node[i] = json_node[i];
+ } //if
+ } //for
+
+ for (var i in json_node.trans) {
+ if (json_node.trans.hasOwnProperty(i)) {
+ trans[i] = json_node.trans[i];
+ } //if
+ } //for
+
+ node.trans = trans;
+ node.id = json_node.id;
+
+ this.octree.insert(node);
+ this.nodes[node.id] = node;
+ }
+ else if (type === "cleaup") {
+ this.octree.cleanup();
+ } //if
+}; //onmessage
+
+/***********************************************
+ * Frustum
+ ***********************************************/
+
+function FrustumWorkerProxy(worker, camera) {
+ this.camera = camera;
+ this.worker = worker;
+ this.draw_on_map = function(map_context) {
+ return;
+ };
+} //FrustumWorkerProxy
+FrustumWorkerProxy.prototype.extract = function(camera, mvMatrix, pMatrix) {
+ this.worker.send({
+ type: "set_camera",
+ data: {
+ mvMatrix: this.camera.mvMatrix,
+ pMatrix: this.camera.pMatrix,
+ position: this.camera.position,
+ target: this.camera.target
+ }
+ });
+}; //FrustumWorkerProxy::extract
+
+function Frustum() {
+ this.last_in = [];
+ this._planes = [];
+ this.sphere = null;
+ for (var i = 0; i < 6; ++i) {
+ this._planes[i] = new Plane();
+ } //for
+} //Frustum::Constructor
+Frustum.prototype.extract = function(camera, mvMatrix, pMatrix) {
+ if (mvMatrix === undef || pMatrix === undef) {
+ return;
+ }
+ var comboMatrix = mat4.multiply(mvMatrix, pMatrix);
+
+ // Left clipping plane
+ this._planes[enums.frustum.plane.LEFT].a = comboMatrix[3] + comboMatrix[0];
+ this._planes[enums.frustum.plane.LEFT].b = comboMatrix[7] + comboMatrix[4];
+ this._planes[enums.frustum.plane.LEFT].c = comboMatrix[11] + comboMatrix[8];
+ this._planes[enums.frustum.plane.LEFT].d = comboMatrix[15] + comboMatrix[12];
+
+ // Right clipping plane
+ this._planes[enums.frustum.plane.RIGHT].a = comboMatrix[3] - comboMatrix[0];
+ this._planes[enums.frustum.plane.RIGHT].b = comboMatrix[7] - comboMatrix[4];
+ this._planes[enums.frustum.plane.RIGHT].c = comboMatrix[11] - comboMatrix[8];
+ this._planes[enums.frustum.plane.RIGHT].d = comboMatrix[15] - comboMatrix[12];
+
+ // Top clipping plane
+ this._planes[enums.frustum.plane.TOP].a = comboMatrix[3] - comboMatrix[1];
+ this._planes[enums.frustum.plane.TOP].b = comboMatrix[7] - comboMatrix[5];
+ this._planes[enums.frustum.plane.TOP].c = comboMatrix[11] - comboMatrix[9];
+ this._planes[enums.frustum.plane.TOP].d = comboMatrix[15] - comboMatrix[13];
+
+ // Bottom clipping plane
+ this._planes[enums.frustum.plane.BOTTOM].a = comboMatrix[3] + comboMatrix[1];
+ this._planes[enums.frustum.plane.BOTTOM].b = comboMatrix[7] + comboMatrix[5];
+ this._planes[enums.frustum.plane.BOTTOM].c = comboMatrix[11] + comboMatrix[9];
+ this._planes[enums.frustum.plane.BOTTOM].d = comboMatrix[15] + comboMatrix[13];
+
+ // Near clipping plane
+ this._planes[enums.frustum.plane.NEAR].a = comboMatrix[3] + comboMatrix[2];
+ this._planes[enums.frustum.plane.NEAR].b = comboMatrix[7] + comboMatrix[6];
+ this._planes[enums.frustum.plane.NEAR].c = comboMatrix[11] + comboMatrix[10];
+ this._planes[enums.frustum.plane.NEAR].d = comboMatrix[15] + comboMatrix[14];
+
+ // Far clipping plane
+ this._planes[enums.frustum.plane.FAR].a = comboMatrix[3] - comboMatrix[2];
+ this._planes[enums.frustum.plane.FAR].b = comboMatrix[7] - comboMatrix[6];
+ this._planes[enums.frustum.plane.FAR].c = comboMatrix[11] - comboMatrix[10];
+ this._planes[enums.frustum.plane.FAR].d = comboMatrix[15] - comboMatrix[14];
+
+ for (var i = 0; i < 6; ++i) {
+ this._planes[i].normalize();
+ }
+
+ //Sphere
+ var fov = 1 / pMatrix[5];
+ var near = -this._planes[enums.frustum.plane.NEAR].d;
+ var far = this._planes[enums.frustum.plane.FAR].d;
+ var view_length = far - near;
+ var height = view_length * fov;
+ var width = height;
+
+ var P = [0, 0, near + view_length * 0.5];
+ var Q = [width, height, near + view_length];
+ var diff = vec3.subtract(P, Q);
+ var diff_mag = vec3.length(diff);
+
+ var look_v = [comboMatrix[3], comboMatrix[9], comboMatrix[10]];
+ var look_mag = vec3.length(look_v);
+ look_v = vec3.multiply(look_v, 1 / look_mag);
+
+ this.sphere = new Sphere([camera.position[0], camera.position[1], camera.position[2]], diff_mag);
+ this.sphere.position = vec3.add(this.sphere.position, vec3.multiply(look_v, view_length * 0.5));
+ this.sphere.position = vec3.add(this.sphere.position, vec3.multiply(look_v, 1));
+
+}; //Frustum::extract
+Frustum.prototype.contains_sphere = function(sphere) {
+ for (var i = 0; i < 6; ++i) {
+ var p = this._planes[i];
+ var normal = [p.a, p.b, p.c];
+ var distance = vec3.dot(normal, sphere.position) + p.d;
+ this.last_in[i] = 1;
+
+ //OUT
+ if (distance < -sphere.radius) {
+ return -1;
+ }
+
+ //INTERSECT
+ if (Math.abs(distance) < sphere.radius) {
+ return 0;
+ }
+
+ } //for
+ //IN
+ return 1;
+}; //Frustum::contains_sphere
+Frustum.prototype.draw_on_map = function(map_canvas, map_context) {
+ var mhw = map_canvas.width/2;
+ var mhh = map_canvas.height/2;
+ map_context.save();
+ for (var pi = 0, l = this._planes.length; pi < l; ++pi) {
+ if (pi === 2 || pi === 3) {continue;}
+ map_context.strokeStyle = "#FF00FF";
+ if (pi < this.last_in.length) {
+ if (this.last_in[pi]) {
+ map_context.strokeStyle = "#FFFF00";
+ }
+ } //if
+ var p = this._planes[pi];
+ var x1 = -mhw;
+ var y1 = (-p.d - p.a * x1) / p.c;
+ var x2 = mhw;
+ var y2 = (-p.d - p.a * x2) / p.c;
+ map_context.moveTo(mhw + x1, mhh + y1);
+ map_context.lineTo(mhw + x2, mhh + y2);
+ map_context.stroke();
+ } //for
+ map_context.strokeStyle = "#0000FF";
+ map_context.beginPath();
+ map_context.arc(mhw + this.sphere.position[0], mhh + this.sphere.position[2], this.sphere.radius, 0, Math.PI * 2, false);
+ map_context.closePath();
+ map_context.stroke();
+ map_context.restore();
+}; //Frustum::draw_on_map
+Frustum.prototype.contains_box = function(bbox) {
+ var total_in = 0;
+
+ var points = [];
+ points[0] = bbox[0];
+ points[1] = [bbox[0][0], bbox[0][1], bbox[1][2]];
+ points[2] = [bbox[0][0], bbox[1][1], bbox[0][2]];
+ points[3] = [bbox[0][0], bbox[1][1], bbox[1][2]];
+ points[4] = [bbox[1][0], bbox[0][1], bbox[0][2]];
+ points[5] = [bbox[1][0], bbox[0][1], bbox[1][2]];
+ points[6] = [bbox[1][0], bbox[1][1], bbox[0][2]];
+ points[7] = bbox[1];
+
+ for (var i = 0; i < 6; ++i) {
+ var in_count = 8;
+ var point_in = 1;
+
+ for (var j = 0; j < 8; ++j) {
+ if (this._planes[i].classify_point(points[j]) === -1) {
+ point_in = 0;
+ --in_count;
+ } //if
+ } //for j
+ this.last_in[i] = point_in;
+
+ //OUT
+ if (in_count === 0) {
+ return -1;
+ }
+
+ total_in += point_in;
+ } //for i
+ //IN
+ if (total_in === 6) {
+ return 1;
+ }
+
+ return 0;
+}; //Frustum::contains_box
+
+function Camera(width, height, fov, nearclip, farclip) {
+ this.frustum = new Frustum();
+
+ if (typeof(width)=='object') {
+ this.position = width.position?width.position:[0, 0, 0];
+ this.rotation = width.rotation?width.rotation:[0, 0, 0];
+ this.target = width.target?width.target:[0, 0, 0];
+ this.fov = width.fov?width.fov:60.0;
+ this.nearclip = width.nearclip?width.nearclip:0.1;
+ this.farclip = width.farclip?width.farclip:400.0;
+ this.targeted = width.targeted?width.targeted:true;
+ height = width.height?width.height:undef;
+ width = width.width?width.width:undef;
+ } else {
+ this.position = [0, 0, 0];
+ this.rotation = [0, 0, 0];
+ this.target = [0, 0, 0];
+ this.fov = (fov !== undef) ? fov : 60.0;
+ this.nearclip = (nearclip !== undef) ? nearclip : 0.1;
+ this.farclip = (farclip !== undef) ? farclip : 400.0;
+ this.targeted = true;
+ }
+
+ this.targetSceneObject = null;
+ this.motion = null;
+ this.transform = new Transform();
+
+ this.manual = false;
+
+ this.setDimensions((width !== undef) ? width : 512, (height !== undef) ? height : 512);
+
+ this.mvMatrix = cubicvr_identity;
+ this.pMatrix = null;
+ this.calcProjection();
+}
+
+Camera.prototype.control = function(controllerId, motionId, value) {
+ if (controllerId === enums.motion.ROT) {
+ this.rotation[motionId] = value;
+ } else if (controllerId === enums.motion.POS) {
+ this.position[motionId] = value;
+ } else if (controllerId === enums.motion.FOV) {
+ this.setFOV(value);
+ } else if (controllerId === enums.motion.LENS) {
+ this.setLENS(value);
+ } else if (controllerId === enums.motion.NEARCLIP) {
+ this.setClip(value,this.farclip);
+ } else if (controllerId === enums.motion.FARCLIP) {
+ this.setClip(this.nearclip,value);
+ }
+ /*
+ switch (controllerId) {
+ case enums.motion.ROT:
+ this.rotation[motionId] = value;
+ break;
+ case enums.motion.POS:
+ this.position[motionId] = value;
+ break;
+ case enums.motion.FOV:
+ this.setFOV(value);
+ break;
+ }
+ */
+};
+
+
+Camera.prototype.makeFrustum = function(left, right, bottom, top, zNear, zFar) {
+ var A = (right + left) / (right - left);
+ var B = (top + bottom) / (top - bottom);
+ var C = -(zFar + zNear) / (zFar - zNear);
+ var D = -2.0 * zFar * zNear / (zFar - zNear);
+
+ return [2.0 * zNear / (right - left), 0.0, 0.0, 0.0, 0.0, 2.0 * zNear / (top - bottom), 0.0, 0.0, A, B, C, -1.0, 0.0, 0.0, D, 0.0];
+};
+
+
+Camera.prototype.setTargeted = function(targeted) {
+ this.targeted = targeted;
+};
+
+Camera.prototype.calcProjection = function() {
+ this.pMatrix = mat4.perspective(this.fov, this.aspect, this.nearclip, this.farclip);
+ if (!this.targeted) {
+ this.transform.clearStack();
+ //this.transform.translate(vec3.subtract([0,0,0],this.position)).pushMatrix().rotate(vec3.subtract([0,0,0],this.rotation)).getResult();
+ this.transform.translate(-this.position[0], -this.position[1], -this.position[2]);
+ this.transform.pushMatrix();
+ this.transform.rotate(-this.rotation[2], 0, 0, 1);
+ this.transform.rotate(-this.rotation[1], 0, 1, 0);
+ this.transform.rotate(-this.rotation[0], 1, 0, 0);
+ this.transform.pushMatrix();
+ this.mvMatrix = this.transform.getResult();
+ this.nMatrix = mat4.inverse_mat3(this.mvMatrix);
+ mat3.transpose_inline(this.nMatrix);
+ }
+ this.frustum.extract(this, this.mvMatrix, this.pMatrix);
+};
+
+
+Camera.prototype.setClip = function(nearclip, farclip) {
+ this.nearclip = nearclip;
+ this.farclip = farclip;
+ this.calcProjection();
+};
+
+
+Camera.prototype.setDimensions = function(width, height) {
+ this.width = width;
+ this.height = height;
+
+ this.aspect = width / height;
+ this.calcProjection();
+};
+
+
+Camera.prototype.setFOV = function(fov) {
+ this.fov = fov;
+ this.calcProjection();
+};
+
+Camera.prototype.setLENS = function(lens) {
+ this.setFOV(2.0*Math.atan(16.0/lens)*(180.0/M_PI));
+};
+
+Camera.prototype.lookat = function(eyeX, eyeY, eyeZ, lookAtX, lookAtY, lookAtZ, upX, upY, upZ) {
+
+ if (typeof(eyeX)=='object') {
+ this.lookat(this.position[0],this.position[1],this.position[2],eyeX[0],eyeX[1],eyeX[2],0,1,0);
+ return;
+ }
+
+ this.mvMatrix = mat4.lookat(eyeX, eyeY, eyeZ, lookAtX, lookAtY, lookAtZ, upX, upY, upZ);
+ this.nMatrix = mat4.inverse_mat3(this.mvMatrix);
+ mat3.transpose_inline(this.nMatrix);
+ this.frustum.extract(this, this.mvMatrix, this.pMatrix);
+};
+
+
+Camera.prototype.unProject = function (winx, winy, winz) {
+
+ var tmpClip = this.nearclip;
+
+ if (tmpClip < 1.0) { this.nearclip = 1.0; this.calcProjection(); }
+
+ var viewport = [0, 0, this.width, this.height];
+
+ if (winz === undef) winz = this.farclip;
+
+ var p = [(((winx - viewport[0]) / (viewport[2])) * 2) - 1, -((((winy - viewport[1]) / (viewport[3])) * 2) - 1), (winz - this.nearclip) / (this.farclip - this.nearclip), 1.0];
+
+ var invp = mat4.vec4_multiply(mat4.vec4_multiply(p, mat4.inverse(this.pMatrix)), mat4.inverse(this.mvMatrix));
+
+ if (tmpClip < 1.0) { this.nearclip = tmpClip; this.calcProjection(); }
+
+ return [invp[0] / invp[3], invp[1] / invp[3], invp[2] / invp[3]];
+}
+
+
+Camera.prototype.project = function (objx, objy, objz) {
+
+ var p = [objx,objy,objz,1.0];
+
+ var mp = mat4.vec4_multiply(mat4.vec4_multiply(p,this.mvMatrix),this.pMatrix);
+
+ return [((mp[0]/mp[3]+1.0)/2.0)*this.width,((-mp[1]/mp[3]+1.0)/2.0)*this.height,((mp[2]/mp[3]))*(this.farclip-this.nearclip)+this.nearclip];
+
+}
+
+
+/*** Auto-Cam Prototype ***/
+
+function AutoCameraNode(pos) {
+ this.position = (pos !== undef) ? pos : [0, 0, 0];
+}
+
+AutoCameraNode.prototype.control = function(controllerId, motionId, value) {
+ if (controllerId === enums.motion.POS) {
+ this.position[motionId] = value;
+ }
+};
+
+function AutoCamera(start_position, target, bounds) {
+ this.camPath = new Motion();
+ this.targetPath = new Motion();
+
+ this.start_position = (start_position !== undef) ? start_position : [8, 8, 8];
+ this.target = (target !== undef) ? target : [0, 0, 0];
+
+ this.bounds = (bounds !== undef) ? bounds : [[-15, 3, -15], [15, 20, 15]];
+
+this.safe_bb = [];
+this.avoid_sphere = [];
+
+this.segment_time = 3.0;
+this.buffer_time = 20.0;
+this.start_time = 0.0;
+this.current_time = 0.0;
+
+this.path_time = 0.0;
+this.path_length = 0;
+
+this.min_distance = 2.0;
+this.max_distance = 40.0;
+
+this.angle_min = 40;
+this.angle_max = 180;
+}
+
+
+AutoCamera.prototype.inBounds = function(pt) {
+ if (! (pt[0] > 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<l; ++i) {
+ var obj = objs[i];
+ if (obj.obj === null) { continue; }
+ if (obj.id < 0) {
+ obj.id = scene_object_uuid;
+ ++scene_object_uuid;
+ } //if
+ this.sceneObjectsById[obj.id] = obj;
+ AABB_reset(obj.octree_aabb, obj.position);
+ this.octree.insert(obj);
+ if (obj.octree_common_root === undefined || obj.octree_common_root === null) {
+ log("!!", obj.name, "octree_common_root is null");
+ } //if
+ } //for
+ } //if
+
+
+} //Scene::attachOctree
+
+Scene.prototype.setSkyBox = function(skybox) {
+ this.skybox = skybox;
+ //this.bindSceneObject(skybox.scene_object, null, false);
+};
+
+Scene.prototype.getSceneObject = function(name) {
+ return this.sceneObjectsByName[name];
+};
+
+Scene.prototype.bindSceneObject = function(sceneObj, pickable, use_octree) {
+ this.sceneObjects.push(sceneObj);
+ if (pickable !== undef) {
+ if (pickable) {
+ this.pickables.push(sceneObj);
+ }
+ }
+
+ if (sceneObj.name !== null) {
+ this.sceneObjectsByName[sceneObj.name] = sceneObj;
+ }
+
+ if (this.octree !== undef && (use_octree === undef || use_octree === "true")) {
+ if (sceneObj.id < 0) {
+ sceneObj.id = scene_object_uuid;
+ ++scene_object_uuid;
+ } //if
+ this.sceneObjectsById[sceneObj.id] = sceneObj;
+ AABB_reset(sceneObj.octree_aabb, sceneObj.position);
+ this.octree.insert(sceneObj);
+ } //if
+};
+
+Scene.prototype.bindLight = function(lightObj, use_octree) {
+ this.lights.push(lightObj);
+ if (this.octree !== undef && (use_octree === undef || use_octree === "true")) {
+ if (lightObj.method === enums.light.method.GLOBAL) {
+ this.global_lights.push(lightObj);
+ }
+ else {
+ if (lightObj.method === enums.light.method.DYNAMIC) {
+ this.dynamic_lights.push(lightObj);
+ } //if
+ this.octree.insert_light(lightObj);
+ } //if
+ } //if
+
+ this.lights=this.lights.sort(cubicvr_lightPackTypes);
+};
+
+Scene.prototype.bindCamera = function(cameraObj) {
+ this.camera = cameraObj;
+};
+
+
+Scene.prototype.evaluate = function(index) {
+ var i,iMax;
+
+ for (i = 0, iMax = this.sceneObjects.length; i < iMax; i++) {
+ if (!(this.sceneObjects[i].motion)) {
+ continue;
+ }
+ this.sceneObjects[i].motion.apply(index, this.sceneObjects[i]);
+ }
+
+ if (this.camera.motion !== null) {
+ if (this.camera.targetSceneObject !== null) {
+ this.camera.target = this.camera.targetSceneObject.position;
+ }
+
+ this.camera.motion.apply(index, this.camera);
+ }
+
+ for (var i = 0, iMax = this.lights.length; i < iMax; i++) {
+ var l = this.lights[i];
+
+ if (l.motion !== null) {
+ l.motion.apply(index, l);
+ }
+ }
+};
+
+Scene.prototype.renderSceneObjectChildren = function(sceneObj) {
+ var gl = GLCore.gl;
+ var sflip = false;
+
+ for (var i = 0, iMax = sceneObj.children.length; i < iMax; i++) {
+
+ try {
+ sceneObj.children[i].doTransform(sceneObj.tMatrix);
+ }catch(e){break;}
+
+ if (sceneObj.children[i].scale[0] < 0) {
+ sflip = !sflip;
+ }
+ if (sceneObj.children[i].scale[1] < 0) {
+ sflip = !sflip;
+ }
+ if (sceneObj.children[i].scale[2] < 0) {
+ sflip = !sflip;
+ }
+
+ if (sflip) {
+ gl.cullFace(gl.FRONT);
+ }
+
+ cubicvr_renderObject(sceneObj.children[i].obj, this.camera, sceneObj.children[i].tMatrix, this.lights);
+
+ if (sflip) {
+ gl.cullFace(gl.BACK);
+ }
+
+ if (sceneObj.children[i].children !== null) {
+ this.renderSceneObjectChildren(sceneObj.children[i]);
+ }
+ }
+};
+
+function cubicvr_lightPackTypes(a,b) {
+ return a.light_type - b.light_type;
+}
+
+Scene.prototype.render = function() {
+ ++this.frames;
+
+ var gl = GLCore.gl;
+ var frustum_hits;
+
+ if (this.camera.manual===false)
+ {
+ if (this.camera.targeted) {
+ this.camera.lookat(this.camera.position[0], this.camera.position[1], this.camera.position[2], this.camera.target[0], this.camera.target[1], this.camera.target[2], 0, 1, 0);
+ } else {
+ this.camera.calcProjection();
+ }
+ }
+
+ var use_octree = this.octree !== undef;
+ var lights_rendered = 0;
+ if (use_octree) {
+ for (var i = 0, l = this.dynamic_lights.length; i < l; ++i) {
+ var light = this.dynamic_lights[i];
+ light.doTransform();
+ } //for
+ this.octree.reset_node_visibility();
+ this.octree.cleanup();
+ frustum_hits = this.octree.get_frustum_hits(this.camera);
+ lights_rendered = frustum_hits.lights.length;
+ } //if
+ var sflip = false;
+ var objects_rendered = 0;
+ var lights_list = [];
+
+ for (var i = 0, iMax = this.sceneObjects.length; i < iMax; i++) {
+
+ var lights = this.lights;
+ var scene_object = this.sceneObjects[i];
+ if (scene_object.parent !== null) {
+ continue;
+ } //if
+
+ scene_object.doTransform();
+
+ if (use_octree)
+ {
+ lights = [];
+ if (scene_object.dirty && scene_object.obj !== null) {
+ scene_object.adjust_octree();
+ } //if
+
+ if (scene_object.visible === false || (use_octree && (scene_object.ignore_octree || scene_object.drawn_this_frame === true || scene_object.culled === true))) {
+ continue;
+ } //if
+
+ //lights = frustum_hits.lights;
+ lights = scene_object.dynamic_lights;
+ //lights = this.lights;
+
+ lights = lights.concat(scene_object.static_lights);
+ lights = lights.concat(this.global_lights);
+ if (this.collect_stats) {
+ lights_rendered = Math.max(lights.length, lights_rendered);
+ if (lights_rendered === lights.length) {
+ lights_list = lights;
+ } //if
+ ++objects_rendered;
+ } //if
+
+ if (lights.length === 0) {
+ lights = [emptyLight];
+ } //if
+
+ scene_object.drawn_this_frame = true;
+ }
+ else if (scene_object.visible === false) {
+ continue;
+ } //if
+
+ if (scene_object.obj !== null) {
+ if (scene_object.scale[0] < 0) {
+ sflip = !sflip;
+ }
+ if (scene_object.scale[1] < 0) {
+ sflip = !sflip;
+ }
+ if (scene_object.scale[2] < 0) {
+ sflip = !sflip;
+ }
+
+ if (sflip) {
+ gl.cullFace(gl.FRONT);
+ }
+
+
+ cubicvr_renderObject(scene_object.obj, this.camera, scene_object.tMatrix, lights.sort(cubicvr_lightPackTypes));
+
+ if (sflip) {
+ gl.cullFace(gl.BACK);
+ }
+
+ sflip = false;
+ } //if
+
+ if (scene_object.children !== null) {
+ this.renderSceneObjectChildren(scene_object);
+ } //if
+ } //for
+
+ if (this.collect_stats) {
+ this.stats['objects.num_rendered'] = objects_rendered;
+ this.stats['lights.num_rendered'] = lights_rendered;
+ this.stats['lights.rendered'] = lights_list;
+ this.stats['lights.num_global'] = this.global_lights.length;
+ this.stats['lights.num_dynamic'] = this.dynamic_lights.length;
+ } //if
+
+ if (this.skybox !== null && this.skybox.ready === true) {
+ gl.cullFace(gl.FRONT);
+ var size = (this.camera.farclip * 2) / Math.sqrt(3.0);
+ this.skybox.scene_object.position = [this.camera.position[0], this.camera.position[1], this.camera.position[2]];
+ this.skybox.scene_object.scale = [size, size, size];
+ this.skybox.scene_object.doTransform();
+ cubicvr_renderObject(this.skybox.scene_object.obj, this.camera, this.skybox.scene_object.tMatrix, []);
+ gl.cullFace(gl.BACK);
+ } //if
+};
+
+Scene.prototype.bbRayTest = function(pos, ray, axisMatch) {
+ var pt1, pt2;
+ var selList = [];
+
+ if (ray.length === 2) {
+ ray = this.camera.unProject(ray[0], ray[1]);
+ } else {
+ ray = vec3.add(pos, ray);
+ }
+
+ pt1 = pos;
+ pt2 = ray;
+
+ for (var obj_i in this.pickables) {
+ if (this.pickables.hasOwnProperty(obj_i)) {
+ var obj = this.pickables[obj_i];
+ if (obj.visible !== true) continue;
+
+ var bb1, bb2;
+ var aabb = obj.getAABB();
+ bb1 = aabb[0];
+ bb2 = aabb[1];
+
+ var mindepth = 0.2;
+
+ if (bb2[0]-bb1[0] < mindepth) {bb1[0] -= mindepth/2; bb2[0] += mindepth/2;}
+ if (bb2[1]-bb1[1] < mindepth) {bb1[1] -= mindepth/2; bb2[1] += mindepth/2;}
+ if (bb2[2]-bb1[2] < mindepth) {bb1[2] -= mindepth/2; bb2[2] += mindepth/2;}
+
+ var center = vec3.multiply(vec3.add(bb1, bb2), 0.5);
+ var testPt = vec3.get_closest_to(pt1, pt2, center);
+ var testDist = vec3.length(vec3.subtract(testPt, center));
+
+ var matches =
+ ((testPt[0] >= 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<b.dist) ?-1:1; });
+ }
+
+ return selList;
+};
+
+function cubicvr_loadMesh(meshUrl, prefix) {
+ if (MeshPool[meshUrl] !== undef) {
+ return MeshPool[meshUrl];
+ }
+
+ var i, j, p, iMax, jMax, pMax;
+
+ var obj = new Mesh();
+ var mesh = util.getXML(meshUrl);
+ var pts_elem = mesh.getElementsByTagName("points");
+
+ var pts_str = util.collectTextNode(pts_elem[0]);
+ var pts = pts_str.split(" ");
+
+ var texName, tex;
+
+ for (i = 0, iMax = pts.length; i < iMax; i++) {
+ pts[i] = pts[i].split(",");
+ for (j = 0, jMax = pts[i].length; j < jMax; j++) {
+ pts[i][j] = parseFloat(pts[i][j]);
+ }
+ }
+
+ obj.addPoint(pts);
+
+ var material_elem = mesh.getElementsByTagName("material");
+ var mappers = [];
+
+
+ for (i = 0, iMax = material_elem.length; i < iMax; i++) {
+ var melem = material_elem[i];
+
+ var matName = (melem.getElementsByTagName("name").length) ? (melem.getElementsByTagName("name")[0].firstChild.nodeValue) : null;
+ var mat = new Material(matName);
+
+ if (melem.getElementsByTagName("alpha").length) {
+ mat.opacity = parseFloat(melem.getElementsByTagName("alpha")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("shininess").length) {
+ mat.shininess = (parseFloat(melem.getElementsByTagName("shininess")[0].firstChild.nodeValue) / 100.0);
+ }
+ if (melem.getElementsByTagName("max_smooth").length) {
+ mat.max_smooth = parseFloat(melem.getElementsByTagName("max_smooth")[0].firstChild.nodeValue);
+ }
+
+ if (melem.getElementsByTagName("color").length) {
+ mat.color = util.floatDelimArray(melem.getElementsByTagName("color")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("ambient").length) {
+ mat.ambient = util.floatDelimArray(melem.getElementsByTagName("ambient")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("diffuse").length) {
+ mat.diffuse = util.floatDelimArray(melem.getElementsByTagName("diffuse")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("specular").length) {
+ mat.specular = util.floatDelimArray(melem.getElementsByTagName("specular")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("texture").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.COLOR);
+ }
+
+ if (melem.getElementsByTagName("texture_luminosity").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_luminosity")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.AMBIENT);
+ }
+
+ if (melem.getElementsByTagName("texture_normal").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_normal")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.NORMAL);
+ }
+
+ if (melem.getElementsByTagName("texture_specular").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_specular")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.SPECULAR);
+ }
+
+ if (melem.getElementsByTagName("texture_bump").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_bump")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.BUMP);
+ }
+
+ if (melem.getElementsByTagName("texture_envsphere").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_envsphere")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.ENVSPHERE);
+ }
+
+ if (melem.getElementsByTagName("texture_alpha").length) {
+ texName = (prefix ? prefix : "") + melem.getElementsByTagName("texture_alpha")[0].firstChild.nodeValue;
+ tex = (Texture_ref[texName] !== undef) ? Textures_obj[Texture_ref[texName]] : (new Texture(texName));
+ mat.setTexture(tex, enums.texture.map.ALPHA);
+ }
+
+ var uvSet = null;
+
+ if (melem.getElementsByTagName("uvmapper").length) {
+ var uvm = new UVMapper();
+ var uvelem = melem.getElementsByTagName("uvmapper")[0];
+ var uvmType = "";
+
+ if (uvelem.getElementsByTagName("type").length) {
+ uvmType = melem.getElementsByTagName("type")[0].firstChild.nodeValue;
+
+ switch (uvmType) {
+ case "uv":
+ break;
+ case "planar":
+ uvm.projection_mode = enums.uv.projection.PLANAR;
+ break;
+ case "cylindrical":
+ uvm.projection_mode = enums.uv.projection.CYLINDRICAL;
+ break;
+ case "spherical":
+ uvm.projection_mode = enums.uv.projection.SPHERICAL;
+ break;
+ case "cubic":
+ uvm.projection_mode = enums.uv.projection.CUBIC;
+ break;
+ }
+ }
+
+ if (uvmType === "uv") {
+ if (uvelem.getElementsByTagName("uv").length) {
+ var uvText = util.collectTextNode(melem.getElementsByTagName("uv")[0]);
+
+ uvSet = uvText.split(" ");
+
+ for (j = 0, jMax = uvSet.length; j < jMax; j++) {
+ uvSet[j] = util.floatDelimArray(uvSet[j]);
+ }
+ }
+ }
+
+ if (uvelem.getElementsByTagName("axis").length) {
+ var uvmAxis = melem.getElementsByTagName("axis")[0].firstChild.nodeValue;
+
+ switch (uvmAxis) {
+ case "x":
+ uvm.projection_axis = enums.uv.axis.X;
+ break;
+ case "y":
+ uvm.projection_axis = enums.uv.axis.Y;
+ break;
+ case "z":
+ uvm.projection_axis = enums.uv.axis.Z;
+ break;
+ }
+
+ }
+
+ if (melem.getElementsByTagName("center").length) {
+ uvm.center = util.floatDelimArray(melem.getElementsByTagName("center")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("rotation").length) {
+ uvm.rotation = util.floatDelimArray(melem.getElementsByTagName("rotation")[0].firstChild.nodeValue);
+ }
+ if (melem.getElementsByTagName("scale").length) {
+ uvm.scale = util.floatDelimArray(melem.getElementsByTagName("scale")[0].firstChild.nodeValue);
+ }
+
+ if (uvmType !== "" && uvmType !== "uv") {
+ mappers.push([uvm, mat]);
+ }
+ }
+
+
+ var seglist = null;
+ var triangles = null;
+
+ if (melem.getElementsByTagName("segments").length) {
+ seglist = util.intDelimArray(util.collectTextNode(melem.getElementsByTagName("segments")[0]), " ");
+ }
+ if (melem.getElementsByTagName("triangles").length) {
+ triangles = util.intDelimArray(util.collectTextNode(melem.getElementsByTagName("triangles")[0]), " ");
+ }
+
+
+ if (seglist === null) {
+ seglist = [0, parseInt((triangles.length) / 3, 10)];
+ }
+
+ var ofs = 0;
+
+ if (triangles.length) {
+ for (p = 0, pMax = seglist.length; p < pMax; p += 2) {
+ var currentSegment = seglist[p];
+ var totalPts = seglist[p + 1] * 3;
+
+ obj.setSegment(currentSegment);
+ obj.setFaceMaterial(mat);
+
+ for (j = ofs, jMax = ofs + totalPts; j < jMax; j += 3) {
+ var newFace = obj.addFace([triangles[j], triangles[j + 1], triangles[j + 2]]);
+ if (uvSet) {
+ obj.faces[newFace].setUV([uvSet[j], uvSet[j + 1], uvSet[j + 2]]);
+ }
+ }
+
+ ofs += totalPts;
+ }
+ }
+ }
+
+ obj.calcNormals();
+
+ for (i = 0, iMax = mappers.length; i < iMax; i++) {
+ mappers[i][0].apply(obj, mappers[i][1]);
+ }
+
+ obj.compile();
+
+ MeshPool[meshUrl] = obj;
+
+ return obj;
+}
+
+
+
+
+
+
+
+function cubicvr_loadScene(sceneUrl, model_prefix, image_prefix) {
+ if (model_prefix === undef) {
+ model_prefix = "";
+ }
+ if (image_prefix === undef) {
+ image_prefix = "";
+ }
+
+ var obj = new Mesh();
+ var scene = util.getXML(sceneUrl);
+
+ var sceneOut = new Scene();
+
+ var parentingSet = [];
+
+ var sceneobjs = scene.getElementsByTagName("sceneobjects");
+
+ var tempNode;
+
+ var position, rotation, scale;
+
+ // var pts_str = util.collectTextNode(pts_elem[0]);
+ for (var i = 0, iMax = sceneobjs[0].childNodes.length; i < iMax; i++) {
+ var sobj = sceneobjs[0].childNodes[i];
+
+ if (sobj.tagName === "sceneobject") {
+
+ var name = "unnamed";
+ var parent = "";
+ var model = "";
+
+ tempNode = sobj.getElementsByTagName("name");
+ if (tempNode.length) {
+ name = util.collectTextNode(tempNode[0]);
+ }
+
+ tempNode = sobj.getElementsByTagName("parent");
+ if (tempNode.length) {
+ parent = util.collectTextNode(tempNode[0]);
+ }
+
+ tempNode = sobj.getElementsByTagName("model");
+ if (tempNode.length) {
+ model = util.collectTextNode(tempNode[0]);
+ }
+
+ position = null;
+ rotation = null;
+ scale = null;
+
+ tempNode = sobj.getElementsByTagName("position");
+ if (tempNode.length) {
+ position = tempNode[0];
+ }
+
+ tempNode = sobj.getElementsByTagName("rotation");
+ if (tempNode.length) {
+ rotation = tempNode[0];
+ }
+
+ tempNode = sobj.getElementsByTagName("scale");
+ if (tempNode.length) {
+ scale = tempNode[0];
+ }
+
+ obj = null;
+
+ if (model !== "") {
+ obj = cubicvr_loadMesh(model_prefix + model, image_prefix);
+ }
+
+ var sceneObject = new SceneObject(obj, name);
+
+ if (cubicvr_isMotion(position)) {
+ if (!sceneObject.motion) {
+ sceneObject.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(position, enums.motion.POS, sceneObject.motion);
+ } else if (position) {
+ sceneObject.position = util.floatDelimArray(util.collectTextNode(position));
+ }
+
+ if (cubicvr_isMotion(rotation)) {
+ if (!sceneObject.motion) {
+ sceneObject.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(rotation, enums.motion.ROT, sceneObject.motion);
+ } else {
+ sceneObject.rotation = util.floatDelimArray(util.collectTextNode(rotation));
+ }
+
+ if (cubicvr_isMotion(scale)) {
+ if (!sceneObject.motion) {
+ sceneObject.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(scale, enums.motion.SCL, sceneObject.motion);
+ } else {
+ sceneObject.scale = util.floatDelimArray(util.collectTextNode(scale));
+
+ }
+
+ sceneOut.bindSceneObject(sceneObject);
+
+ if (parent !== "") {
+ parentingSet.push([sceneObject, parent]);
+ }
+ }
+ }
+
+ for (var j in parentingSet) {
+ if (parentingSet.hasOwnProperty(j)) {
+ sceneOut.getSceneObject(parentingSet[j][1]).bindChild(parentingSet[j][0]);
+ }
+ }
+
+ var camera = scene.getElementsByTagName("camera");
+
+ if (camera.length) {
+ position = null;
+ rotation = null;
+
+ var target = "";
+
+ tempNode = camera[0].getElementsByTagName("name");
+
+ var cam = sceneOut.camera;
+
+ var fov = null;
+
+ if (tempNode.length) {
+ target = tempNode[0].firstChild.nodeValue;
+ }
+
+ tempNode = camera[0].getElementsByTagName("target");
+ if (tempNode.length) {
+ target = tempNode[0].firstChild.nodeValue;
+ }
+
+ if (target !== "") {
+ cam.targetSceneObject = sceneOut.getSceneObject(target);
+ }
+
+ tempNode = camera[0].getElementsByTagName("position");
+ if (tempNode.length) {
+ position = tempNode[0];
+ }
+
+ tempNode = camera[0].getElementsByTagName("rotation");
+ if (tempNode.length) {
+ rotation = tempNode[0];
+ }
+
+ tempNode = camera[0].getElementsByTagName("fov");
+ if (tempNode.length) {
+ fov = tempNode[0];
+ }
+
+ if (cubicvr_isMotion(position)) {
+ if (!cam.motion) {
+ cam.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(position, enums.motion.POS, cam.motion);
+ } else if (position) {
+ cam.position = util.floatDelimArray(position.firstChild.nodeValue);
+ }
+
+ if (cubicvr_isMotion(rotation)) {
+ if (!cam.motion) {
+ cam.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(rotation, enums.motion.ROT, cam.motion);
+ } else if (rotation) {
+ cam.rotation = util.floatDelimArray(rotation.firstChild.nodeValue);
+ }
+
+ if (cubicvr_isMotion(fov)) {
+ if (!cam.motion) {
+ cam.motion = new Motion();
+ }
+ cubicvr_nodeToMotion(fov, enums.motion.FOV, cam.motion);
+ } else if (fov) {
+ cam.fov = parseFloat(fov.firstChild.nodeValue);
+ }
+
+ }
+
+
+ return sceneOut;
+}
+
+
+function RenderBuffer(width, height, depth_enabled) {
+ this.createBuffer(width, height, depth_enabled);
+}
+
+RenderBuffer.prototype.createBuffer = function(width, height, depth_enabled) {
+ this.fbo = null;
+ this.depth = null;
+ this.texture = null;
+ this.width = parseInt(width, 10);
+ this.height = parseInt(height, 10);
+
+ var w = this.sizeParam(width);
+ var h = this.sizeParam(height);
+
+ var gl = GLCore.gl;
+
+ this.fbo = gl.createFramebuffer();
+
+ if (depth_enabled) {
+ this.depth = gl.createRenderbuffer();
+ }
+
+ // configure fbo
+ gl.bindFramebuffer(gl.FRAMEBUFFER, this.fbo);
+
+ if (depth_enabled) {
+ gl.bindRenderbuffer(gl.RENDERBUFFER, this.depth);
+
+ if (navigator.appVersion.indexOf("Windows")!==-1 || 1)
+ {
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depth);
+ }
+ else
+ {
+ gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, w, h);
+ gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.depth);
+ }
+ }
+
+
+ // if (depth_enabled) {
+ // gl.bindRenderbuffer(gl.RENDERBUFFER, this.depth);
+ // gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h);
+ // }
+
+ // GL_DEPTH_COMPONENT32 0x81A7
+ // if (depth_enabled) { gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT, w, h); }
+ // if (depth_enabled) {
+ // gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depth);
+ // }
+
+
+
+ // init texture
+ this.texture = new Texture();
+ gl.bindTexture(gl.TEXTURE_2D, Textures[this.texture.tex_id]);
+
+ // configure texture params
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ 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);
+
+ // clear buffer
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
+
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, Textures[this.texture.tex_id], 0);
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+};
+
+RenderBuffer.prototype.destroyBuffer = function() {
+ var gl = GLCore.gl;
+
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+ gl.deleteRenderbuffer(this.depth);
+ gl.deleteFramebuffer(this.fbo);
+ gl.deleteTexture(Textures[this.texture.tex_id]);
+ Textures[this.texture.tex_id] = null;
+};
+
+RenderBuffer.prototype.sizeParam = function(t) {
+ return t;
+ // var s = 32;
+ //
+ // while (t > 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<this.meshBin[binId].length)
+ {
+ this.meshBinPtr[binId]++;
+ return this.meshBin[binId][cBin];
+ }
+
+ return null;
+ };
+
+ DeferredBin.prototype.loadNextMesh = function(binId)
+ {
+ var mesh = this.getNextMesh(binId);
+
+ if (mesh !== null)
+ {
+ if (mesh.compiled===null)
+ {
+ mesh.triangulateQuads();
+ mesh.compile();
+ mesh.clean();
+ }
+
+ return true;
+ }
+
+ return false;
+ };
+
+ DeferredBin.prototype.isMeshBinEmpty = function(binId) {
+ //console.log('isMeshBinEmpty[' + binId + '] = ' + (this.meshBinPtr[binId] === this.meshBin[binId].length) + ' meshBinPtr = ' + this.meshBinPtr[binId] + ' meshBin.length = ' + this.meshBin[binId].length);
+ return this.meshBinPtr[binId] === this.meshBin[binId].length;
+ };
+
+ DeferredBin.prototype.loadNextImage = function(binId)
+ {
+ var img = this.getNextImage(binId);
+
+ if (img !== null) {
+ img.src = img.deferredSrc;
+// return true;
+ }
+
+// return false;
+ };
+
+
+ DeferredBin.prototype.getNextImage = function(binId) {
+ var cBin = this.imageBinPtr[binId];
+
+ if (cBin<this.imageBin[binId].length)
+ {
+ this.imageBinPtr[binId]++;
+ return this.imageBin[binId][cBin];
+ }
+
+ return null;
+ };
+
+ DeferredBin.prototype.isImageBinEmpty = function(binId) {
+ //console.log('isImageBinEmpty[' + binId + '] = ' + (this.imageBinPtr[binId] === this.imageBin[binId].length));
+ return this.imageBinPtr[binId] === this.imageBin[binId].length ;
+ };
+
+function cubicvr_loadColladaWorker(meshUrl, prefix, callback, deferred_bin) {
+ var worker;
+ try {
+ worker = new Worker(SCRIPT_LOCATION + 'collada.js');
+ }
+ catch(e) {
+ throw new Error("Can't find collada.js");
+ } //try
+
+ var materials_map = [];
+ var meshes_map = [];
+
+ worker.onmessage = function(e) {
+
+ function copyObjectFromJSON(json, obj) {
+ for (var i in json) {
+ obj[i] = json[i];
+ } //for
+ } //new_obj
+
+ var message = e.data.message;
+ if (message == 'materials') {
+ var mats = JSON.parse(e.data.data);
+ for (var i=0, maxI=mats.length; i<maxI; ++i) {
+ var new_mat = new Material(mats[i].name);
+ var mat_id = new_mat.material_id;
+ copyObjectFromJSON(mats[i], new_mat);
+ new_mat.material_id = mat_id;
+ materials_map[mats[i].material_id] = mat_id;
+ for (var j=0, maxJ=mats[i].textures.length; j<maxJ; ++j) {
+ var dt = mats[i].textures[j];
+ if (dt) {
+ var stored_tex = Texture_ref[dt.img_path];
+
+ if (stored_tex === undefined) {
+ var t = new Texture(dt.img_path, dt.filter_type, deferred_bin, meshUrl);
+ new_mat.textures[j] = t;
+ }
+ else {
+ new_mat.textures[j] = Textures_obj[stored_tex];
+ } //if
+ }
+ else {
+ new_mat.textures[j] = 0;
+ } //if
+ } //for
+ } //for
+ }
+ else if (message == 'scene') {
+ var scene = JSON.parse(e.data.data);
+
+ function reassembleMotion(obj) {
+ //reassemble linked-list for sceneObject motion envelope keys
+ if (obj.motion) {
+ var co = obj.motion.controllers;
+ var new_controllers = [];
+ for (var j=0, maxJ=co.length; j<maxJ; ++j) {
+ var con = co[j];
+ if (!con) {
+ co[j] = undefined;
+ continue;
+ }
+ var new_con = [];
+ for (var k=0, maxK=con.length; k<maxK; ++k) {
+ var env = con[k];
+ if (!env) {
+ con[k] = undefined;
+ continue;
+ }
+ var keys = env.keys[0];
+ if (env.keys.length > 1) {
+ keys.prev = null;
+ keys.next = env.keys[1];
+ keys = env.keys[1];
+ } //if
+ for (var keyI=1,maxKeyI=env.keys.length-1; keyI<maxKeyI; ++keyI) {
+ keys.prev = env.keys[keyI-1];
+ keys.next = env.keys[keyI+1];
+ keys = env.keys[keyI+1];
+ } //for keyI
+ if (env.keys.length > 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<maxI; ++i) {
+ var so = scene.sceneObjects[i];
+
+ if (so.obj !== null) {
+
+ } //if
+
+ if (so.reassembled === undefined) {
+ reassembleMotion(so);
+ so.reassembled = true;
+ } //if
+
+ function createSceneObject(scene_obj) {
+ var sceneObject = new SceneObject();
+ copyObjectFromJSON(scene_obj, sceneObject);
+ if (scene_obj.obj !== null) {
+ var stored_mesh = meshes_map[scene_obj.obj.id];
+ if (stored_mesh === undefined) {
+ var mesh = new Mesh();
+ copyObjectFromJSON(scene_obj.obj, mesh);
+ sceneObject.obj = mesh;
+ meshes_map[scene_obj.obj.id] = mesh;
+ if (deferred_bin) {
+ if (mesh.points.length > 0) {
+ deferred_bin.addMesh(meshUrl,meshUrl+":"+mesh.id,mesh)
+ for (var f=0,maxF=mesh.faces.length; f<maxF; ++f) {
+ var face = mesh.faces[f];
+ var m_index = face.material;
+ var mapped = materials_map[m_index];
+ if (mapped !== undefined) {
+ face.material = materials_map[m_index];
+ }
+ else {
+ face.material = 0;
+ } //if
+ } //for
+ } //if
+ }
+ else {
+ sceneObject.obj.triangulateQuads();
+ sceneObject.obj.calcNormals();
+ sceneObject.obj.compile();
+ sceneObject.obj.clean();
+ } //if
+ }
+ else {
+ sceneObject.obj = stored_mesh;
+ } //if
+ } //if
+
+ sceneObject.trans = new Transform();
+
+ if (scene_obj.children && scene_obj.children.length > 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<maxJ; ++j) {
+ var child = createSceneObject(scene_obj.children[j]);
+ sceneObject.bindChild(child);
+ } //for
+ } //if
+ } //createChildren
+
+ scene.sceneObjects[i] = createSceneObject(so);
+
+ } //for i
+
+ var new_scene = new Scene();
+ // place parsed scene elements into new scene (since parse scene has no prototype)
+ var camera = new_scene.camera;
+ var camera_transform = camera.transform;
+ copyObjectFromJSON(scene.camera, camera);
+ copyObjectFromJSON(scene.camera.transform, camera_transform);
+ reassembleMotion(camera);
+ new_scene.camera = camera;
+ new_scene.camera.transform = camera_transform;
+ new_scene.camera.frustum = new Frustum();
+
+ for (var i=0, maxI=scene.sceneObjects.length; i<maxI; ++i) {
+ var o = scene.sceneObjects[i];
+ new_scene.bindSceneObject(o);
+ try {
+ o.getAABB();
+ }
+ catch(e) {
+ //console.log(o);
+ } //try
+
+ } //for
+
+ for (var i=0, maxI=scene.lights.length; i<maxI; ++i) {
+ var l = new Light();
+ copyObjectFromJSON(scene.lights[i], l);
+ l.trans = new Transform();
+ reassembleMotion(l);
+ new_scene.bindLight(l);
+ } //for
+
+ callback(new_scene);
+ }
+ else {
+ console.log("message from collada worker:", e.data.message);
+ } //if
+ } //onmessage
+
+ worker.onerror = function(e) {
+ console.log("error from collada worker:", e.message);
+ } //onerror
+
+ worker.postMessage({message:'start', params: {meshUrl: meshUrl, prefix: prefix, rootDir: SCRIPT_LOCATION}});
+} //cubicvr_loadColladaWorker
+
+
+function xml2badgerfish(xmlDoc) {
+ var jsonData = {};
+ var nodeStack = [];
+
+ var i, iMax, iMin;
+
+ var n = xmlDoc;
+ var j = jsonData;
+ var cn, tn;
+ var regEmpty = /^\s+|\s+$/g;
+
+ xmlDoc.jsonParent = j;
+ nodeStack.push(xmlDoc);
+
+ while (nodeStack.length) {
+ var n = nodeStack.pop();
+ var tagGroup = null;
+
+ j = n.jsonParent;
+
+ for (i = 0, iMax = n.childNodes.length; i < iMax; i++) {
+ cn = n.childNodes[i];
+ tn = cn.tagName;
+
+ if (tn !== undef) {
+ tagGroup = tagGroup || {};
+ tagGroup[tn] = tagGroup[tn] || 0;
+ tagGroup[tn]++;
+ }
+ }
+
+ if (n.attributes) if (n.attributes.length) {
+ for (i = 0, iMax = n.attributes.length; i < iMax; i++) {
+ var att = n.attributes[i];
+
+ j["@" + att.name] = att.value;
+ }
+ }
+
+ for (i = 0, iMax = n.childNodes.length; i < iMax; i++) {
+ cn = n.childNodes[i];
+ tn = cn.tagName;
+
+ if (cn.nodeType === 1) {
+ if (tagGroup[tn] > 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)"));
+}());
+